diff options
382 files changed, 39681 insertions, 9716 deletions
diff --git a/.coveragerc b/.coveragerc index f67853192..3ad7f68a6 100644 --- a/.coveragerc +++ b/.coveragerc @@ -14,4 +14,4 @@ source = yardstick [report] ignore_errors = True precision = 3 -omit = yardstick/vTC/* +omit = yardstick/vTC/*,yardstick/tests/functional/* @@ -2,8 +2,8 @@ Project: Test framework for verifying infrastructure compliance (yardstick) Project Creation Date: April 28th, 2015 Project Category: Integration & Testing Lifecycle State: Incubation -Primary Contact: ross.b.brattain@intel.com -Project Lead: ross.b.brattain@intel.com +Primary Contact: limingjiang@huawei.com +Project Lead: limingjiang@huawei.com Jira Project Name: Infrastructure Verification Jira Project Prefix: Yardstick Mailing list tag: [Yardstick] @@ -4,11 +4,11 @@ project_creation_date: 'April 28th, 2015' project_category: 'Integration & Testing' lifecycle_state: 'Incubation' project_lead: &opnfv_yardstick_ptl - name: 'Ross Brattain' - email: 'ross.b.brattain@intel.com' - id: 'rbbratta' - company: 'intel.com' - timezone: 'PST' + name: 'Rex Lee' + email: 'limingjiang@huawei.com' + company: 'huawei.com' + id: 'rexlee8776' + timezone: 'UTC+8' primary_contact: *opnfv_yardstick_ptl issue_tracking: type: 'jira' @@ -24,12 +24,12 @@ realtime_discussion: channel: '#opnfv-yardstick' meetings: - type: 'gotomeeting+irc' - agenda: 'https://wiki.opnfv.org/display/yardstick/Yardstick+Meetings' - url: 'https://global.gotomeeting.com/join/819733085' + agenda: 'https://wiki.opnfv.org/display/yardstick/Yardstick+Meetings' + url: 'https://global.gotomeeting.com/join/819733085' server: 'freenode.net' channel: '#opnfv-yardstick' repeats: 'weekly' - time: '08:30 UTC' + time: '08:30 UTC' repositories: - 'yardstick' committers: @@ -38,10 +38,6 @@ committers: email: 'jean.gaoliang@huawei.com' company: 'huawei.com' id: 'kubi' - - name: 'Rex Lee' - email: 'limingjiang@huawei.com' - company: 'huawei.com' - id: 'rexlee8776' - name: 'Jing Lu' email: 'lvjing5@huawei.com' company: 'huawei.com' @@ -74,6 +70,10 @@ committers: email: 'abhijit.sinha@intel.com' company: 'intel.com' id: 'abhijitsinha' + - name: 'Ross Brattain' + email: 'ross.b.brattain@intel.com' + id: 'rbbratta' + company: 'intel.com' tsc: # yamllint disable rule:line-length approval: 'http//meetbot.opnfv.org/meetings/' diff --git a/ansible/install-inventory.ini b/ansible/install-inventory.ini new file mode 100644 index 000000000..6aa9905bd --- /dev/null +++ b/ansible/install-inventory.ini @@ -0,0 +1,30 @@ +# the group of systems on which to install yardstick +# by default just localhost +[jumphost] +#yardstickvm1 ansible_user=ubuntu ansible_ssh_pass=password ansible_connection=local +localhost ansible_connection=local + +# section below is only due backward compatibility. +# it will be removed later +[yardstick:children] +jumphost + +[yardstick-standalone] +#yardstickvm2 ansible_host=192.168.2.51 ansible_user=ubuntu ansible_ssh_pass=password ansible_connection=ssh +# uncomment hosts below if you would to test yardstick-standalone/sriov scenarios +#yardstick-standalone-node ansible_host=192.168.1.2 +#yardstick-standalone-node-2 ansible_host=192.168.1.3 + +[yardstick-baremetal] +#yardstickvm3 ansible_host=192.168.2.52 ansible_user=ubuntu ansible_ssh_pass=password ansible_connection=ssh +# hostname ansible_host=192.168.1.2 + +[all:vars] +arch_amd64=amd64 +arch_arm64=arm64 +inst_mode_container=container +inst_mode_baremetal=baremetal +ubuntu_archive={"amd64": "http://archive.ubuntu.com/ubuntu/", "arm64": "http://ports.ubuntu.com/ubuntu-ports/"} +# uncomment credentials below for yardstick-standalone +#ansible_user=root +#ansible_pass=root diff --git a/ansible/install.yaml b/ansible/install.yaml index c446b91f7..ae9f8587f 100644 --- a/ansible/install.yaml +++ b/ansible/install.yaml @@ -1,14 +1,20 @@ +# Copyright (c) 2018 Intel Corporation. +# +# 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. --- -- hosts: localhost - +- hosts: jumphost + become: yes vars: - arch_amd64: "amd64" - arch_arm64: "arm64" - inst_mode_container: "container" - inst_mode_baremetal: "baremetal" - ubuntu_archive: - amd64: "http://archive.ubuntu.com/ubuntu/" - arm64: "http://ports.ubuntu.com/ubuntu-ports/" installation_mode: "{{ INSTALLATION_MODE | default('baremetal') }}" yardstick_dir: "{{ YARDSTICK_DIR | default('/home/opnfv/repos/yardstick') }}" virtual_environment: "{{ VIRTUAL_ENVIRONMENT | default(False) }}" @@ -29,6 +35,7 @@ - install_yardstick - configure_uwsgi - configure_nginx + - configure_gui - download_trex - install_trex - configure_rabbitmq @@ -42,3 +49,52 @@ - shell: uwsgi -i /etc/yardstick/yardstick.ini when: installation_mode != inst_mode_container + +- name: Prepare baremetal and standalone server(s) + hosts: yardstick-baremetal,yardstick-standalone + become: yes + vars: + YARD_IMG_ARCH: "{{ arch_amd64 }}" + environment: + proxy_env: + http_proxy: "{{ lookup('env', 'http_proxy') }}" + https_proxy: "{{ lookup('env', 'https_proxy') }}" + ftp_proxy: "{{ lookup('env', 'ftp_proxy') }}" + no_proxy: "{{ lookup('env', 'no_proxy') }}" + + roles: + - add_custom_repos + - role: set_package_installer_proxy + when: proxy_env is defined and proxy_env + # can't update grub in chroot/docker + - enable_hugepages_on_boot + # needed for collectd plugins + - increase_open_file_limits + - install_image_dependencies + - role: download_dpdk + # dpdk_version: "17.02" + - install_dpdk + - download_trex + - install_trex + - download_civetweb + - install_civetweb + - download_samplevnfs + - role: install_samplevnf + vnf_name: PROX + - role: install_samplevnf + vnf_name: UDP_Replay + - role: install_samplevnf + vnf_name: ACL + - role: install_samplevnf + vnf_name: FW + - role: install_samplevnf + vnf_name: CGNAPT + # build shared DPDK for collectd only, required DPDK downloaded already + - install_dpdk_shared + - install_rabbitmq + - download_intel_cmt_cat + - install_intel_cmt_cat + - download_pmu_tools + - install_pmu_tools + - download_collectd + - install_collectd diff --git a/ansible/install_trex_standalone.yml b/ansible/install_trex_standalone.yml deleted file mode 100644 index 9cf64142b..000000000 --- a/ansible/install_trex_standalone.yml +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright (c) 2017 Intel Corporation. -# -# 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. ---- -- hosts: yardstick - vars: - ansible_python_interpreter: "/usr/bin/env python" - # needed for virtualenv - NSB_INSTALL_DIR: /root/nsb_install - INSTALL_BIN_PATH: /opt/nsb_bin - #TREX_DOWNLOAD: "https://trex-tgn.cisco.com/trex/release/v2.05.tar.gz" - TREX_VERSION: v2.20 - TREX_DOWNLOAD: "https://trex-tgn.cisco.com/trex/release/{{ TREX_VERSION }}.tar.gz" - - tasks: - - get_url: - url: "{{ TREX_DOWNLOAD }}" - dest: "{{ NSB_INSTALL_DIR }}" - checksum: "sha256:b9620341e552d2ef71d5ffa39ef92f12a1186836c250390db77bd7228497b91c" - - - unarchive: - src: "{{ NSB_INSTALL_DIR }}/{{ TREX_DOWNLOAD|basename }}" - dest: "{{ NSB_INSTALL_DIR }}" - copy: no - - - file: path="{{ INSTALL_BIN_PATH }}/trex" state=absent - - file: path="{{ INSTALL_BIN_PATH }}/trex" state=directory - - - command: mv "{{ NSB_INSTALL_DIR }}/{{ TREX_DOWNLOAD|basename|regex_replace('\.tar.gz', '') }}" "{{ INSTALL_BIN_PATH }}/trex/scripts" - - - file: path="{{ INSTALL_BIN_PATH }}/trex/scripts/automation/trex_control_plane/stl/__init__.py" state=touch - - - command: cp "{{ INSTALL_BIN_PATH }}/trex/scripts/dpdk_nic_bind.py" "{{ INSTALL_BIN_PATH }}" - - - name: add scripts to PYTHONPATH - lineinfile: - dest: /etc/environment - regexp: "^PYTHONPATH=" - line: "PYTHONPATH={{ INSTALL_BIN_PATH }}/trex/scripts/automation/trex_control_plane:{{ INSTALL_BIN_PATH }}/trex/scripts/automation/trex_control_plane/stl:{{ NSB_INSTALL_DIR }}/yardstick" - state: present - create: yes diff --git a/ansible/roles/configure_nginx/tasks/main.yml b/ansible/roles/configure_nginx/tasks/main.yml index 37b052725..e0f7f75bb 100644 --- a/ansible/roles/configure_nginx/tasks/main.yml +++ b/ansible/roles/configure_nginx/tasks/main.yml @@ -30,4 +30,4 @@ shell: | semanage port -m -t http_port_t -p tcp 5000 semanage port -m -t http_port_t -p udp 5000 - when: ansible_os_family == "RedHat"
\ No newline at end of file + when: ansible_os_family == "RedHat" diff --git a/ansible/roles/configure_uwsgi/templates/yardstick.ini.j2 b/ansible/roles/configure_uwsgi/templates/yardstick.ini.j2 index c049daf84..495febb19 100644 --- a/ansible/roles/configure_uwsgi/templates/yardstick.ini.j2 +++ b/ansible/roles/configure_uwsgi/templates/yardstick.ini.j2 @@ -1,7 +1,7 @@ [uwsgi] master = true debug = true -chdir = {{ yardstick_dir }}api +chdir = {{ yardstick_dir }}/api module = server plugins = python processes = 10 @@ -12,7 +12,7 @@ chmod-socket = 666 callable = app_wrapper enable-threads = true close-on-exec = 1 -daemonize = {{ log_dir }}uwsgi.log +logto = {{ log_dir }}/uwsgi.log socket = {{ socket_file }} {# If virtual environment, we need to add: - virtualenv = <virtual_env> #}
\ No newline at end of file + virtualenv = <virtual_env> #} diff --git a/ansible/roles/download_dpdk/defaults/main.yml b/ansible/roles/download_dpdk/defaults/main.yml index d548280f5..885eebf03 100644 --- a/ansible/roles/download_dpdk/defaults/main.yml +++ b/ansible/roles/download_dpdk/defaults/main.yml @@ -1,14 +1,18 @@ --- -dpdk_version: "17.02" -dpdk_url: "http://dpdk.org/browse/dpdk/snapshot/dpdk-{{ dpdk_version }}.tar.gz" +dpdk_version: "17.02.1" +dpdk_url: "http://fast.dpdk.org/rel/dpdk-{{ dpdk_version }}.tar.xz" dpdk_file: "{{ dpdk_url|basename }}" -dpdk_unarchive: "{{ dpdk_file|regex_replace('[.]tar[.]gz$', '') }}" +dpdk_unarchive: "{{ dpdk_file|regex_replace('[.]tar[.]xz$', '') }}" dpdk_dest: "{{ clone_dest }}/" -#Note DPDK 17.08 17.11 and 18.02 are currently unsupported due to prox build issues -dpdk_sha256s: - "16.07": "sha256:d876e4b2a7101f28e7e345d3c88e66afe877d15f0159c19c5bc5bc26b7b7d788" - "17.02": "sha256:b07b546e910095174bdb6152bb0d7ce057cc4b79aaa74771aeee4e8a7219fb38" - "17.05": "sha256:763bfb7e1765efcc949e79d645dc9f1ebd16591431ba0db5ce22becd928dcd0a" - "17.08": "sha256:3a08addbff45c636538514e9a5838fb91ea557661a4c071e03a9a6987d46e5b6" #unsupported - "17.11": "sha256:77a727bb3834549985f291409c9a77a1e8be1c9329ce4c3eb19a22d1461022e4" #unsupported - "18.02": "sha256:f1210310fd5f01a3babe3a09d9b3e5a9db791c2ec6ecfbf94ade9f893a0632b8" #unsupported + +#NOTE(ralonsoh): DPDK > 17.02 are currently unsupported due to prox build issues +dpdk_md5: + "16.07.2": "md5:4922ea2ec935b64ff5c191fec53344a6" + "16.11.7": "md5:c081d113dfd57633e3bc3ebc802691be" + "17.02.1": "md5:cbdf8b7a92ce934d47c38cbc9c20c54a" + "17.05": "md5:0a68c31cd6a6cabeed0a4331073e4c05" #Ubuntu 17.10 support + "17.05.2": "md5:37afc9ce410d8e6945a1beb173074003" #unsupported + "17.08.2": "md5:dd239a878c8c40cf482fdfe438f8d99c" #unsupported + "17.11.3": "md5:68ca84ac878011acf44e75d33b46f55b" #unsupported + "18.02.2": "md5:75ad6d39b513649744e49c9fcbbb9ca5" #unsupported + "18.05": "md5:9fc86367cd9407ff6a8dfea56c4eddc4" #unsupported diff --git a/ansible/roles/download_dpdk/tasks/main.yml b/ansible/roles/download_dpdk/tasks/main.yml index bcb5dde1a..55b466cb7 100644 --- a/ansible/roles/download_dpdk/tasks/main.yml +++ b/ansible/roles/download_dpdk/tasks/main.yml @@ -25,7 +25,7 @@ url: "{{ dpdk_url }}" dest: "{{ dpdk_dest }}" validate_certs: False - checksum: "{{ dpdk_sha256s[dpdk_version] }}" + checksum: "{{ dpdk_md5[dpdk_version] }}" - unarchive: src: "{{ dpdk_dest }}/{{ dpdk_file }}" @@ -37,8 +37,20 @@ path: "{{ dpdk_dest }}/{{ dpdk_file }}" state: absent +- name: find unzipped DPDK folder + find: + paths: "{{ dpdk_dest }}" + patterns: "^dpdk-.*{{ dpdk_version }}$" + file_type: directory + use_regex: yes + register: dpdk_folder_match + +- fail: + msg: "Cannot find unzipped DPDK folder or more than one found" + when: dpdk_folder_match.matched != 1 + - set_fact: - dpdk_path: "{{ dpdk_dest }}/{{ dpdk_unarchive }}" + dpdk_path: "{{ dpdk_folder_match.files[0].path }}" - set_fact: RTE_SDK: "{{ dpdk_path }}" diff --git a/ansible/roles/download_samplevnfs/defaults/main.yml b/ansible/roles/download_samplevnfs/defaults/main.yml index e40eb67c0..c5e880e57 100644 --- a/ansible/roles/download_samplevnfs/defaults/main.yml +++ b/ansible/roles/download_samplevnfs/defaults/main.yml @@ -1,4 +1,4 @@ --- samplevnf_url: "https://git.opnfv.org/samplevnf" samplevnf_dest: "{{ clone_dest }}/samplevnf" -samplevnf_version: "stable/euphrates" +samplevnf_version: "stable/fraser" diff --git a/ansible/roles/download_trex/defaults/main.yml b/ansible/roles/download_trex/defaults/main.yml index 6e8fa7020..cbaae1d84 100644 --- a/ansible/roles/download_trex/defaults/main.yml +++ b/ansible/roles/download_trex/defaults/main.yml @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. --- -trex_version: v2.28 +trex_version: v2.41 trex_url: "https://trex-tgn.cisco.com/trex/release/{{ trex_version }}.tar.gz" trex_file: "{{ trex_url|basename }}" trex_unarchive: "{{ trex_file|regex_replace('[.]tar.gz$', '') }}" @@ -20,3 +20,4 @@ trex_dest: "{{ clone_dest }}/" trex_sha256s: "v2.20": "sha256:eb5a069f758a36133a185c7e27af10834ca03d11441165403529fbd7844658fb" "v2.28": "sha256:c3f08aabbd69dddb09843984d41acbe9ba1af6a6ef3380a7830f7c9e33134207" + "v2.41": "sha256:aa4122d82cc7b25a16a20d6dd465eccd89e31c51816d4103765b86d06a8b9810" diff --git a/ansible/roles/infra_create_vms/tasks/main.yml b/ansible/roles/infra_create_vms/tasks/main.yml index 4d47f44ff..b422a9205 100644 --- a/ansible/roles/infra_create_vms/tasks/main.yml +++ b/ansible/roles/infra_create_vms/tasks/main.yml @@ -32,3 +32,14 @@ loop_control: loop_var: node_item with_items: "{{ infra_deploy_vars.nodes }}" + +- name: Create list of dictionaries with vm name, ip address + set_fact: + vm_name_ip: "{{ vm_name_ip|default([]) + [{item.hostname: item.interfaces[1].ip}] }}" + with_items: "{{ infra_deploy_vars.nodes }}" + +- name: Make sure VM is reachable + include_tasks: validate_vms.yml + loop_control: + loop_var: name_ip + with_items: "{{ vm_name_ip }}" diff --git a/ansible/roles/infra_create_vms/tasks/validate_vms.yml b/ansible/roles/infra_create_vms/tasks/validate_vms.yml new file mode 100644 index 000000000..ce5eff211 --- /dev/null +++ b/ansible/roles/infra_create_vms/tasks/validate_vms.yml @@ -0,0 +1,54 @@ +# Copyright (c) 2018 Intel Corporation. +# +# 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. +--- +- name: Validate if VM is responding + wait_for: + host: "{{ item.value }}" + port: 22 + timeout: 10 + with_dict: "{{ name_ip }}" + register: result + ignore_errors: yes + +- name: Stop VM if it is not responding + virt: + name: "{{ item.key }}" + command: destroy + when: result is failed + with_dict: "{{ name_ip }}" + +- name: Wait for VM is being stopped + pause: + seconds: 10 + when: result is failed + +- name: Start VM + virt: + name: "{{ item.key }}" + command: start + when: result is failed + with_dict: "{{ name_ip }}" + +- name: Validate if VM is responding + wait_for: + host: "{{ item.value }}" + port: 22 + timeout: 10 + when: result is failed + with_dict: "{{ name_ip }}" + register: result + +- fail: + msg: "FAILED on {{ name_ip }}" + when: result is failed diff --git a/ansible/roles/infra_prepare_vms/tasks/main.yml b/ansible/roles/infra_prepare_vms/tasks/main.yml index d7ed08511..4e0d9c373 100644 --- a/ansible/roles/infra_prepare_vms/tasks/main.yml +++ b/ansible/roles/infra_prepare_vms/tasks/main.yml @@ -100,6 +100,3 @@ secondary_ip: "{{ item.interfaces[1].ip }}" when: item.hostname == 'yardstickvm' with_items: "{{ infra_deploy_vars.nodes }}" - -- name: Workaround, not all VMs are ready by that time - pause: seconds=20 diff --git a/ansible/roles/install_dpdk/tasks/main.yml b/ansible/roles/install_dpdk/tasks/main.yml index 5bcfb50b1..f89a43cae 100644 --- a/ansible/roles/install_dpdk/tasks/main.yml +++ b/ansible/roles/install_dpdk/tasks/main.yml @@ -114,9 +114,16 @@ path: "{{ INSTALL_BIN_PATH }}" state: directory +- set_fact: + major: "{{ dpdk_version.split('.')[0] }}" + minor: "{{ dpdk_version.split('.')[1] }}" + +- set_fact: + major_minor_version: "{{ major }}.{{ minor }}" + - name: copy dpdk-devbind.py to correct location copy: - src: "{{ dpdk_devbind_usertools if dpdk_version|float >= 17.02 else dpdk_devbind_tools }}" + src: "{{ dpdk_devbind_usertools if major_minor_version|float >= 17.02 else dpdk_devbind_tools }}" dest: "{{ INSTALL_BIN_PATH }}/dpdk-devbind.py" remote_src: yes force: yes diff --git a/ansible/roles/install_samplevnf/vars/main.yml b/ansible/roles/install_samplevnf/vars/main.yml index 45cea6820..e2a37377a 100644 --- a/ansible/roles/install_samplevnf/vars/main.yml +++ b/ansible/roles/install_samplevnf/vars/main.yml @@ -47,12 +47,12 @@ vnf_build_dependencies: vnf_build_dirs: ACL: vACL FW: vFW - CGNATP: vCGNAPT + CGNAPT: vCGNAPT UDP_Replay: UDP_Replay PROX: DPPD-PROX vnf_app_names: ACL: vACL FW: vFW - CGNATP: vCGNAPT + CGNAPT: vCGNAPT UDP_Replay: UDP_Replay PROX: prox diff --git a/ansible/roles/install_trex/defaults/main.yml b/ansible/roles/install_trex/defaults/main.yml index a5555e355..79a04fedd 100644 --- a/ansible/roles/install_trex/defaults/main.yml +++ b/ansible/roles/install_trex/defaults/main.yml @@ -13,6 +13,6 @@ # limitations under the License. --- #TREX_DOWNLOAD: "https://trex-tgn.cisco.com/trex/release/v2.05.tar.gz" -TREX_VERSION: v2.28 +TREX_VERSION: v2.41 TREX_DOWNLOAD: "{{ nsb_mirror_url|ternary(nsb_mirror_url, 'https://trex-tgn.cisco.com/trex/release' }}/{{ TREX_VERSION }}.tar.gz" INSTALL_BIN_PATH: "/opt/nsb_bin" diff --git a/ansible/roles/install_yardstick/tasks/main.yml b/ansible/roles/install_yardstick/tasks/main.yml index ee1b83756..203acc3e5 100644 --- a/ansible/roles/install_yardstick/tasks/main.yml +++ b/ansible/roles/install_yardstick/tasks/main.yml @@ -37,10 +37,39 @@ # name: pip # state: latest -- name: install yardstick without virtual environment - include_tasks: regular_install.yml +- name: Install Yardstick requirements (venv) + pip: + requirements: "{{ yardstick_dir }}/requirements.txt" + virtualenv: "{{ yardstick_dir }}/virtualenv" + async: 900 + poll: 0 + register: pip_installer + when: virtual_environment == True + +- name: Install Yardstick requirements + pip: + requirements: "{{ yardstick_dir }}/requirements.txt" + async: 900 + poll: 0 + register: pip_installer when: virtual_environment == False -- name: install yardstick with virtual environment - include_tasks: virtual_install.yml +- name: Check install Yardstick requirements + async_status: + jid: "{{ pip_installer.ansible_job_id }}" + register: job_result + until: job_result.finished + retries: 180 + +- name: Install Yardstick code (venv) + pip: + name: "{{ yardstick_dir }}/" + editable: True + virtualenv: "{{ yardstick_dir }}/virtualenv" when: virtual_environment == True + +- name: Install Yardstick code + pip: + name: "{{ yardstick_dir }}/" + editable: True + when: virtual_environment == False diff --git a/ansible/roles/install_yardstick/tasks/regular_install.yml b/ansible/roles/install_yardstick/tasks/regular_install.yml deleted file mode 100644 index 4a9925ab4..000000000 --- a/ansible/roles/install_yardstick/tasks/regular_install.yml +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright (c) 2018 Intel Corporation. -# -# 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. ---- -- name: Install Yardstick requirements - pip: - requirements: "{{ yardstick_dir }}/requirements.txt" - -- name: Install Yardstick code - pip: - name: "{{ yardstick_dir }}/." - extra_args: -e diff --git a/ansible/roles/install_yardstick/tasks/virtual_install.yml b/ansible/roles/install_yardstick/tasks/virtual_install.yml deleted file mode 100644 index 8545acbcb..000000000 --- a/ansible/roles/install_yardstick/tasks/virtual_install.yml +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright (c) 2018 Intel Corporation. -# -# 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. ---- -- name: Install Yardstick requirements - pip: - requirements: "{{ yardstick_dir }}/requirements.txt" - virtualenv: "{{ yardstick_dir }}/virtualenv" - -- name: Install Yardstick code - pip: - name: "{{ yardstick_dir }}/." - extra_args: -e - virtualenv: "{{ yardstick_dir }}/virtualenv" - diff --git a/ansible/ubuntu_server_baremetal_deploy_samplevnfs.yml b/ansible/ubuntu_server_baremetal_deploy_samplevnfs.yml index 479b45c92..3a29a8a90 100644 --- a/ansible/ubuntu_server_baremetal_deploy_samplevnfs.yml +++ b/ansible/ubuntu_server_baremetal_deploy_samplevnfs.yml @@ -44,7 +44,7 @@ - role: install_samplevnf vnf_name: FW - role: install_samplevnf - vnf_name: CGNATP + vnf_name: CGNAPT # build shared DPDK for collectd only, required DPDK downloaded already - install_dpdk_shared - install_rabbitmq diff --git a/ansible/ubuntu_server_cloudimg_modify_samplevnfs.yml b/ansible/ubuntu_server_cloudimg_modify_samplevnfs.yml index 7aa6c8c12..b27933bd1 100644 --- a/ansible/ubuntu_server_cloudimg_modify_samplevnfs.yml +++ b/ansible/ubuntu_server_cloudimg_modify_samplevnfs.yml @@ -54,7 +54,7 @@ - role: install_samplevnf vnf_name: FW - role: install_samplevnf - vnf_name: CGNATP + vnf_name: CGNAPT # build shared DPDK for collectd only, required DPDK downloaded already - install_dpdk_shared - install_rabbitmq diff --git a/ansible/yardstick-install-inventory.ini b/ansible/yardstick-install-inventory.ini deleted file mode 100644 index e276076cc..000000000 --- a/ansible/yardstick-install-inventory.ini +++ /dev/null @@ -1,20 +0,0 @@ -# the group of systems on which to install yardstick -# by default just localhost -[jumphost] -localhost ansible_connection=local - -# section below is only due backward compatibility. -# it will be removed later -[yardstick:children] -jumphost - -[yardstick-standalone] -# uncomment hosts below if you would to test yardstick-standalone/sriov scenarios -#yardstick-standalone-node ansible_host=192.168.1.2 -#yardstick-standalone-node-2 ansible_host=192.168.1.2 - -[all:vars] -# incomment credentials below for yardstick-standalone -#ansible_user=root -#ansible_pass=root - diff --git a/api/resources/v2/openrcs.py b/api/resources/v2/openrcs.py index cb506d0e8..4706b856a 100644 --- a/api/resources/v2/openrcs.py +++ b/api/resources/v2/openrcs.py @@ -21,6 +21,7 @@ from yardstick.common import constants as consts from yardstick.common.utils import result_handler from yardstick.common.utils import makedirs from yardstick.common.utils import source_env +from yardstick.common import exceptions as y_exc LOG = logging.getLogger(__name__) LOG.setLevel(logging.DEBUG) @@ -57,7 +58,7 @@ class V2Openrcs(ApiResource): openrc_data = self._get_openrc_dict() except Exception: LOG.exception('parse openrc failed') - return result_handler(consts.API_ERROR, 'parse openrc failed') + raise y_exc.UploadOpenrcError() openrc_id = str(uuid.uuid4()) self._write_into_database(environment_id, openrc_id, openrc_data) @@ -67,7 +68,7 @@ class V2Openrcs(ApiResource): self._generate_ansible_conf_file(openrc_data) except Exception: LOG.exception('write cloud conf failed') - return result_handler(consts.API_ERROR, 'genarate ansible conf failed') + raise y_exc.UploadOpenrcError() LOG.info('finish writing ansible cloud conf') return result_handler(consts.API_SUCCESS, {'openrc': openrc_data, 'uuid': openrc_id}) @@ -102,7 +103,7 @@ class V2Openrcs(ApiResource): source_env(consts.OPENRC) except Exception: LOG.exception('source openrc failed') - return result_handler(consts.API_ERROR, 'source openrc failed') + raise y_exc.UpdateOpenrcError() LOG.info('source openrc: Done') openrc_id = str(uuid.uuid4()) @@ -113,7 +114,7 @@ class V2Openrcs(ApiResource): self._generate_ansible_conf_file(openrc_vars) except Exception: LOG.exception('write cloud conf failed') - return result_handler(consts.API_ERROR, 'genarate ansible conf failed') + raise y_exc.UpdateOpenrcError() LOG.info('finish writing ansible cloud conf') return result_handler(consts.API_SUCCESS, {'openrc': openrc_vars, 'uuid': openrc_id}) @@ -174,7 +175,7 @@ class V2Openrcs(ApiResource): makedirs(consts.OPENSTACK_CONF_DIR) with open(consts.CLOUDS_CONF, 'w') as f: - yaml.dump(ansible_conf, f, default_flow_style=False) + yaml.safe_dump(ansible_conf, f, default_flow_style=False) class V2Openrc(ApiResource): diff --git a/api/server.py b/api/server.py index 37a1ab6a6..914fe8457 100644 --- a/api/server.py +++ b/api/server.py @@ -39,11 +39,13 @@ app.config['MAX_CONTENT_LENGTH'] = 2 * 1024 * 1024 * 1024 Swagger(app) -api = Api(app) +api = Api(app, errors=consts.API_ERRORS) @app.teardown_request def shutdown_session(exception=None): + if exception: + LOG.warning(exception.message) db_session.remove() diff --git a/api/utils/influx.py b/api/utils/influx.py index 9bc6e9abe..f391ad972 100644 --- a/api/utils/influx.py +++ b/api/utils/influx.py @@ -6,15 +6,19 @@ # which accompanies this distribution, and is available at # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -from __future__ import absolute_import import logging -import six.moves.configparser as ConfigParser -from six.moves.urllib.parse import urlsplit -from influxdb import InfluxDBClient +from six.moves import configparser as ConfigParser +# NOTE(ralonsoh): pylint E0401 import error +# https://github.com/PyCQA/pylint/issues/1640 +from six.moves.urllib.parse import urlsplit # pylint: disable=relative-import +from influxdb import client as influxdb_client from yardstick.common import constants as consts +from yardstick.common import exceptions +from yardstick import dispatcher + logger = logging.getLogger(__name__) @@ -23,22 +27,22 @@ def get_data_db_client(): parser = ConfigParser.ConfigParser() try: parser.read(consts.CONF_FILE) - - if parser.get('DEFAULT', 'dispatcher') != 'influxdb': - raise RuntimeError - - return _get_client(parser) + return _get_influxdb_client(parser) except ConfigParser.NoOptionError: - logger.error('can not find the key') + logger.error('Can not find the key') raise -def _get_client(parser): +def _get_influxdb_client(parser): + if dispatcher.INFLUXDB not in parser.get('DEFAULT', 'dispatcher'): + raise exceptions.InfluxDBConfigurationMissing() + ip = _get_ip(parser.get('dispatcher_influxdb', 'target')) user = parser.get('dispatcher_influxdb', 'username') password = parser.get('dispatcher_influxdb', 'password') db_name = parser.get('dispatcher_influxdb', 'db_name') - return InfluxDBClient(ip, consts.INFLUXDB_PORT, user, password, db_name) + return influxdb_client.InfluxDBClient(ip, consts.INFLUXDB_PORT, user, + password, db_name) def _get_ip(url): diff --git a/dashboard/Prox_BM_L3FWD-4Port-1507803878020.json b/dashboard/Prox_BM_L3FWD-4Port-1507803878020.json deleted file mode 100644 index 09184cb2d..000000000 --- a/dashboard/Prox_BM_L3FWD-4Port-1507803878020.json +++ /dev/null @@ -1,1151 +0,0 @@ -{ - "__inputs": [ - { - "name": "DS_YARDSTICK", - "label": "yardstick", - "description": "", - "type": "datasource", - "pluginId": "influxdb", - "pluginName": "InfluxDB" - } - ], - "__requires": [ - { - "type": "grafana", - "id": "grafana", - "name": "Grafana", - "version": "4.4.3" - }, - { - "type": "panel", - "id": "graph", - "name": "Graph", - "version": "" - }, - { - "type": "datasource", - "id": "influxdb", - "name": "InfluxDB", - "version": "1.0.0" - }, - { - "type": "panel", - "id": "text", - "name": "Text", - "version": "" - } - ], - "annotations": { - "list": [] - }, - "editable": true, - "gnetId": null, - "graphTooltip": 0, - "hideControls": false, - "id": null, - "links": [], - "refresh": false, - "rows": [ - { - "collapse": false, - "height": "100px", - "panels": [ - { - "content": "<h5 style=\"font-family:Verdana\"> <a style=\"color:#31A7D3\"><a style=\"font: 32px '#31A7D3'\"><center>OPNFV_Yardstick_NSB_PROX_BM_L3Fwd_4Port_Test</center> </a></h5>\n<center>\n<p>The application performs routing of packets with LPM based look-up method.\nThe KPI is the number of packets per second for a specified packet size with an accepted minimal packet loss </p>\n</center>", - "editable": true, - "error": false, - "id": 3, - "links": [], - "mode": "html", - "span": 12, - "title": "", - "type": "text" - }, - { - "content": "<h5 style=\"font-family:Verdana\"> <a style=\"color:#31A7D3\"><a style=\"font: 22px '#31A7D3'\"><center>Prox L3Fwd VNF stats</center> </a></h5>\n", - "editable": true, - "error": false, - "height": "40", - "id": 7, - "links": [], - "mode": "html", - "span": 12, - "title": "", - "type": "text" - } - ], - "repeat": null, - "repeatIteration": null, - "repeatRowId": null, - "showTitle": false, - "title": "Row", - "titleSize": "h6" - }, - { - "collapse": false, - "height": "300px", - "panels": [ - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "${DS_YARDSTICK}", - "editable": true, - "error": false, - "fill": 1, - "grid": {}, - "height": "300", - "id": 4, - "legend": { - "alignAsTable": true, - "avg": true, - "current": false, - "max": true, - "min": true, - "rightSide": false, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 2, - "links": [], - "nullPointMode": "connected", - "percentage": false, - "pointradius": 1, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "span": 12, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "VNF packets Forward", - "dsType": "influxdb", - "groupBy": [ - { - "params": [ - "$interval" - ], - "type": "time" - }, - { - "params": [ - "null" - ], - "type": "fill" - } - ], - "measurement": "tc_prox_baremetal_l3fwd-4", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "vnf__0.packets_fwd" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [] - }, - { - "alias": "VNF packets in", - "dsType": "influxdb", - "groupBy": [ - { - "params": [ - "$interval" - ], - "type": "time" - }, - { - "params": [ - "null" - ], - "type": "fill" - } - ], - "measurement": "tc_prox_baremetal_l3fwd-4", - "policy": "default", - "refId": "C", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "vnf__0.packets_in" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [] - }, - { - "alias": "VNF packets dropped", - "dsType": "influxdb", - "groupBy": [ - { - "params": [ - "$interval" - ], - "type": "time" - }, - { - "params": [ - "null" - ], - "type": "fill" - } - ], - "measurement": "tc_prox_heat_context_l3fwd-4", - "policy": "default", - "refId": "B", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "vnf__0.packets_dropped" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [] - } - ], - "thresholds": [ - { - "colorMode": "custom", - "fill": true, - "fillColor": "rgba(216, 200, 27, 0.27)", - "op": "gt", - "value": 2 - }, - { - "colorMode": "custom", - "fill": true, - "fillColor": "rgba(234, 112, 112, 0.22)", - "op": "gt", - "value": 2 - } - ], - "timeFrom": null, - "timeShift": null, - "title": "VNF stats: Packet In, Forward and Dropped", - "tooltip": { - "msResolution": true, - "shared": true, - "sort": 0, - "value_type": "cumulative" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": "Packets", - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "content": "<h5 style=\"font-family:Verdana\"> <a style=\"color:#31A7D3\"><a style=\"font: 22px '#31A7D3'\"><center>Prox L3Fwd Traffic Gen stats</center> </a></h5>\n", - "editable": true, - "error": false, - "height": "40", - "id": 8, - "links": [], - "mode": "html", - "span": 12, - "title": "", - "type": "text" - } - ], - "repeat": null, - "repeatIteration": null, - "repeatRowId": null, - "showTitle": false, - "title": "New row", - "titleSize": "h6" - }, - { - "collapse": false, - "height": "300px", - "panels": [ - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "${DS_YARDSTICK}", - "editable": true, - "error": false, - "fill": 1, - "grid": {}, - "id": 6, - "legend": { - "alignAsTable": true, - "avg": true, - "current": false, - "max": true, - "min": true, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 2, - "links": [], - "nullPointMode": "connected", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "span": 6, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "TG xe-0 Out packets", - "dsType": "influxdb", - "groupBy": [ - { - "params": [ - "$interval" - ], - "type": "time" - }, - { - "params": [ - "null" - ], - "type": "fill" - } - ], - "measurement": "tc_prox_baremetal_l3fwd-4", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "tg__0.xe0.out_packets" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [] - }, - { - "alias": "TG xe-1 Out packets", - "dsType": "influxdb", - "groupBy": [ - { - "params": [ - "$interval" - ], - "type": "time" - }, - { - "params": [ - "null" - ], - "type": "fill" - } - ], - "measurement": "tc_prox_baremetal_l3fwd-4", - "policy": "default", - "refId": "B", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "tg__0.xe1.out_packets" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [] - }, - { - "alias": "TG xe-2 Out packets", - "dsType": "influxdb", - "groupBy": [ - { - "params": [ - "$interval" - ], - "type": "time" - }, - { - "params": [ - "null" - ], - "type": "fill" - } - ], - "measurement": "tc_prox_baremetal_l3fwd-4", - "policy": "default", - "refId": "C", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "tg__0.xe2.out_packets" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [] - }, - { - "alias": "TG xe-3 Out packets", - "dsType": "influxdb", - "groupBy": [ - { - "params": [ - "$interval" - ], - "type": "time" - }, - { - "params": [ - "null" - ], - "type": "fill" - } - ], - "measurement": "tc_prox_baremetal_l3fwd-4", - "policy": "default", - "refId": "D", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "tg__0.xe3.out_packets" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [] - } - ], - "thresholds": [ - { - "colorMode": "custom", - "fill": true, - "fillColor": "rgba(216, 200, 27, 0.27)", - "op": "gt", - "value": 2 - }, - { - "colorMode": "custom", - "fill": true, - "fillColor": "rgba(234, 112, 112, 0.22)", - "op": "gt", - "value": 2 - } - ], - "timeFrom": null, - "timeShift": null, - "title": "TG Port Stats: Out packets", - "tooltip": { - "msResolution": true, - "shared": true, - "sort": 0, - "value_type": "cumulative" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": "Packets", - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "${DS_YARDSTICK}", - "editable": true, - "error": false, - "fill": 1, - "grid": {}, - "id": 9, - "legend": { - "alignAsTable": true, - "avg": true, - "current": false, - "max": true, - "min": true, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 2, - "links": [], - "nullPointMode": "connected", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "span": 6, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "TG xe-0 in packets", - "dsType": "influxdb", - "groupBy": [ - { - "params": [ - "$interval" - ], - "type": "time" - }, - { - "params": [ - "null" - ], - "type": "fill" - } - ], - "measurement": "tc_prox_baremetal_l3fwd-4", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "tg__0.xe0.in_packets" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [] - }, - { - "alias": "TG xe-1 in packets", - "dsType": "influxdb", - "groupBy": [ - { - "params": [ - "$interval" - ], - "type": "time" - }, - { - "params": [ - "null" - ], - "type": "fill" - } - ], - "measurement": "tc_prox_baremetal_l3fwd-4", - "policy": "default", - "refId": "B", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "tg__0.xe1.in_packets" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [] - }, - { - "alias": "TG xe-2 in packets", - "dsType": "influxdb", - "groupBy": [ - { - "params": [ - "$interval" - ], - "type": "time" - }, - { - "params": [ - "null" - ], - "type": "fill" - } - ], - "measurement": "tc_prox_baremetal_l3fwd-4", - "policy": "default", - "refId": "C", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "tg__0.xe2.in_packets" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [] - }, - { - "alias": "TG xe-3 in packets", - "dsType": "influxdb", - "groupBy": [ - { - "params": [ - "$interval" - ], - "type": "time" - }, - { - "params": [ - "null" - ], - "type": "fill" - } - ], - "measurement": "tc_prox_baremetal_l3fwd-4", - "policy": "default", - "refId": "D", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "tg__0.xe3.in_packets" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [] - } - ], - "thresholds": [ - { - "colorMode": "custom", - "fill": true, - "fillColor": "rgba(216, 200, 27, 0.27)", - "op": "gt", - "value": 2 - }, - { - "colorMode": "custom", - "fill": true, - "fillColor": "rgba(234, 112, 112, 0.22)", - "op": "gt", - "value": 2 - } - ], - "timeFrom": null, - "timeShift": null, - "title": "TG Port Stats: In packets", - "tooltip": { - "msResolution": true, - "shared": true, - "sort": 0, - "value_type": "cumulative" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": "Packets", - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - } - ], - "repeat": null, - "repeatIteration": null, - "repeatRowId": null, - "showTitle": false, - "title": "New row", - "titleSize": "h6" - }, - { - "collapse": false, - "height": "250px", - "panels": [ - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "${DS_YARDSTICK}", - "editable": true, - "error": false, - "fill": 1, - "grid": {}, - "id": 2, - "legend": { - "alignAsTable": true, - "avg": true, - "current": false, - "max": true, - "min": true, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 2, - "links": [], - "nullPointMode": "connected", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "span": 6, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "TG TX Throughput", - "dsType": "influxdb", - "groupBy": [ - { - "params": [ - "$interval" - ], - "type": "time" - }, - { - "params": [ - "null" - ], - "type": "fill" - } - ], - "measurement": "tc_prox_baremetal_l3fwd-4", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "tg__0.TxThroughput" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [] - }, - { - "alias": "TG RX Throughput", - "dsType": "influxdb", - "groupBy": [ - { - "params": [ - "$interval" - ], - "type": "time" - }, - { - "params": [ - "null" - ], - "type": "fill" - } - ], - "measurement": "tc_prox_baremetal_l3fwd-4", - "orderByTime": "ASC", - "policy": "default", - "refId": "B", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "tg__0.RxThroughput" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [] - } - ], - "thresholds": [ - { - "colorMode": "custom", - "fill": true, - "fillColor": "rgba(216, 200, 27, 0.27)", - "op": "gt", - "value": 2 - }, - { - "colorMode": "custom", - "fill": true, - "fillColor": "rgba(234, 112, 112, 0.22)", - "op": "gt", - "value": 2 - } - ], - "timeFrom": null, - "timeShift": null, - "title": "TG Throughput Stats", - "tooltip": { - "msResolution": true, - "shared": true, - "sort": 0, - "value_type": "cumulative" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": "Throughput in MPPS", - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "${DS_YARDSTICK}", - "editable": true, - "error": false, - "fill": 1, - "grid": {}, - "id": 5, - "legend": { - "alignAsTable": true, - "avg": true, - "current": false, - "max": true, - "min": true, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 2, - "links": [], - "nullPointMode": "connected", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "span": 6, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "TG Packet Size", - "dsType": "influxdb", - "groupBy": [ - { - "params": [ - "$interval" - ], - "type": "time" - }, - { - "params": [ - "null" - ], - "type": "fill" - } - ], - "measurement": "tc_prox_baremetal_l3fwd-4", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "tg__0.PktSize" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [] - } - ], - "thresholds": [ - { - "colorMode": "custom", - "fill": true, - "fillColor": "rgba(216, 200, 27, 0.27)", - "op": "gt", - "value": 2 - }, - { - "colorMode": "custom", - "fill": true, - "fillColor": "rgba(234, 112, 112, 0.22)", - "op": "gt", - "value": 2 - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Packet size", - "tooltip": { - "msResolution": true, - "shared": true, - "sort": 0, - "value_type": "cumulative" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "decbytes", - "label": "Packet Size", - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - } - ], - "repeat": null, - "repeatIteration": null, - "repeatRowId": null, - "showTitle": false, - "title": "New row", - "titleSize": "h6" - }, - { - "collapse": false, - "height": "250px", - "panels": [], - "repeat": null, - "repeatIteration": null, - "repeatRowId": null, - "showTitle": false, - "title": "New row", - "titleSize": "h6" - } - ], - "schemaVersion": 14, - "style": "dark", - "tags": [ - "NSB", - "Prox", - "BM", - "4Port", - "L3Fwd" - ], - "templating": { - "list": [] - }, - "time": { - "from": "2017-09-29T14:12:51.977Z", - "to": "2017-09-29T14:19:29.296Z" - }, - "timepicker": { - "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ], - "time_options": [ - "5m", - "15m", - "1h", - "6h", - "12h", - "24h", - "2d", - "7d", - "30d" - ] - }, - "timezone": "browser", - "title": "Prox_BM_L3FWD-4Port", - "version": 4 -}
\ No newline at end of file diff --git a/dashboard/Prox_BM_L3FWD-4Port-1529606919144.json b/dashboard/Prox_BM_L3FWD-4Port-1529606919144.json new file mode 100644 index 000000000..6f6adcc36 --- /dev/null +++ b/dashboard/Prox_BM_L3FWD-4Port-1529606919144.json @@ -0,0 +1,12735 @@ +{ + "__inputs": [ + { + "name": "DS_YARDSTICK", + "label": "yardstick", + "description": "", + "type": "datasource", + "pluginId": "influxdb", + "pluginName": "InfluxDB" + } + ], + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "5.2.0-beta2" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph", + "version": "5.0.0" + }, + { + "type": "datasource", + "id": "influxdb", + "name": "InfluxDB", + "version": "5.0.0" + }, + { + "type": "panel", + "id": "singlestat", + "name": "Singlestat", + "version": "5.0.0" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "5.0.0" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": null, + "links": [], + "panels": [ + { + "content": "<h5 style=\"font-family:Verdana\"> <a style=\"color:#31A7D3\"><a style=\"font: 32px '#31A7D3'\"><center>OPNFV_Yardstick_NSB_PROX_BM_L3FWD_4Port_Test</center> </a></h5>\n<center>\n<p>The application does Port forwarding without touching packets. It will take packets in from one port and forward them unmodified to another port </p>\n<p>The KPI is the number of packets per second for a specified packet size with an accepted minimal packet loss </p>\n</center>", + "editable": true, + "error": false, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 3, + "links": [], + "mode": "html", + "title": "", + "type": "text" + }, + { + "content": "<h5 style=\"font-family:Verdana\"> <a style=\"color:#31A7D3\"><a style=\"font: 32px '#31A7D3'\"><center>Test Parameters</center> </a></h5>", + "gridPos": { + "h": 2, + "w": 12, + "x": 12, + "y": 0 + }, + "id": 136, + "links": [], + "mode": "html", + "title": "", + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 12, + "y": 2 + }, + "height": "35", + "id": 12, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.duration" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": "", + "title": "Test Interval", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 15, + "y": 2 + }, + "height": "30", + "id": 13, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "alias": "Test Precision", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.test_precision" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": "", + "title": "Test Precision", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 18, + "y": 2 + }, + "height": "30", + "id": 11, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "alias": "Test Duration", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.test_duration" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": "", + "title": "Test Duration", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 21, + "y": 2 + }, + "height": "30", + "id": 14, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "alias": "Tolerated Loss", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.tolerated_loss" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": "", + "title": "Tolerated Loss", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "fill": 1, + "gridPos": { + "h": 10, + "w": 24, + "x": 0, + "y": 5 + }, + "id": 123, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": true, + "min": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "Cumulative Packets Sents", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "vnf__0.packets_fwd" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": [ + { + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(216, 200, 27, 0.27)", + "line": true, + "lineColor": "rgba(0, 0, 0, 0)", + "op": "gt", + "value": 0 + }, + { + "colorMode": "custom", + "fill": true, + "fillColor": "rgb(234, 112, 112, 0.22)", + "line": true, + "lineColor": "rgba(0, 0, 0, 0.01)", + "op": "gt", + "value": 0 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Cumulative Load Sent by Generator", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Packets Per Second", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "<h5 style=\"font-family:Verdana\"> <a style=\"color:#31A7D3\"><a style=\"font: 22px '#31A7D3'\"><center>Throughput</center> </a></h5>\n", + "editable": true, + "error": false, + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 15 + }, + "height": "40", + "id": 7, + "links": [], + "minSpan": 24, + "mode": "html", + "title": "", + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "editable": true, + "error": false, + "fill": 1, + "grid": {}, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 18 + }, + "id": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": true, + "min": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "targets": [ + { + "alias": "Load Requested to Generator", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.RequestedTxThroughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + }, + { + "alias": "Load Generated (by the Generator)", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.TxThroughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + }, + { + "alias": "Load Received (by the Generator)", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "hide": false, + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.RxThroughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": [ + { + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(216, 200, 27, 0.27)", + "op": "gt", + "value": 0 + }, + { + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(234, 112, 112, 0.22)", + "op": "gt", + "value": 0 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Generator stats", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "transparent": false, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Million Packets Per Second", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_YARDSTICK}", + "editable": true, + "error": false, + "fill": 1, + "grid": {}, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 18 + }, + "id": 5, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": true, + "min": true, + "show": true, + "sort": "min", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "targets": [ + { + "alias": "Packet Size", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.PktSize" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": [ + { + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(216, 200, 27, 0.27)", + "op": "gt", + "value": 0 + }, + { + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(234, 112, 112, 0.22)", + "op": "gt", + "value": 0 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Packet Size", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "none", + "label": "Packet Size (Bytes)", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": "%L ine Rate", + "logBase": 1, + "max": "100", + "min": "0", + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "editable": true, + "error": false, + "fill": 1, + "grid": {}, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 27 + }, + "height": "300", + "id": 4, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 1, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "targets": [ + { + "alias": "SUT Packets Received", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "C", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "vnf__0.curr_packets_in" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + }, + { + "params": [ + " / 1000000" + ], + "type": "math" + } + ] + ], + "tags": [] + } + ], + "thresholds": [ + { + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(216, 200, 27, 0.27)", + "op": "gt", + "value": 0 + }, + { + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(234, 112, 112, 0.22)", + "op": "gt", + "value": 0 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "SUT Stats - Load Received By SUT", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Million Packets per Second", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "editable": true, + "error": false, + "fill": 1, + "grid": {}, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 27 + }, + "height": "300", + "id": 39, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 1, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "targets": [ + { + "alias": "SUT Packets Sent", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "vnf__0.curr_packets_fwd" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + }, + { + "params": [ + " / 1000000" + ], + "type": "math" + } + ] + ], + "tags": [] + } + ], + "thresholds": [ + { + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(216, 200, 27, 0.27)", + "op": "gt", + "value": 0 + }, + { + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(234, 112, 112, 0.22)", + "op": "gt", + "value": 0 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "SUT Stats - Load Forwarded By SUT", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Million Packets per Second", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "<h5 style=\"font-family:Verdana\"> <a style=\"color:#31A7D3\"><a style=\"font: 22px '#31A7D3'\"><center>Prox L3FWD Traffic Gen stats</center> </a></h5>\n", + "editable": true, + "error": false, + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 35 + }, + "height": "40", + "id": 8, + "links": [], + "minSpan": 24, + "mode": "html", + "title": "", + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "editable": true, + "error": false, + "fill": 1, + "grid": {}, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 38 + }, + "id": 43, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": true, + "min": true, + "show": true, + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "targets": [ + { + "alias": "TG xe-0 Out packets", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.xe0.out_packets" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + }, + { + "alias": "TG xe-1 Out packets", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.xe1.out_packets" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + }, + { + "alias": "TG xe-2 Out packets", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "C", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.xe2.out_packets" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + }, + { + "alias": "TG xe-3 Out packets", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "D", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.xe3.out_packets" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": [ + { + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(216, 200, 27, 0.27)", + "op": "gt", + "value": 0 + }, + { + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(234, 112, 112, 0.22)", + "op": "gt", + "value": 0 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Packets Sent by Generator", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Packets ", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_YARDSTICK}", + "editable": true, + "error": false, + "fill": 1, + "grid": {}, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 38 + }, + "id": 9, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": true, + "min": true, + "show": true, + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "TG xe-0 in packets", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.xe0.in_packets" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + }, + { + "alias": "TG xe-1 in packets", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.xe1.in_packets" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + }, + { + "alias": "TG xe-2 in packets", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "C", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.xe2.in_packets" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + }, + { + "alias": "TG xe-3 in packets", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "D", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.xe3.in_packets" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": [ + { + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(216, 200, 27, 0.27)", + "op": "gt", + "value": 0 + }, + { + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(234, 112, 112, 0.22)", + "op": "gt", + "value": 0 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Packets Received by Generator", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Packets Per Second", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_YARDSTICK}", + "fill": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 48 + }, + "id": 10, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": true, + "min": true, + "show": true, + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "SUCCESS Tx Total", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_tx_total" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + }, + { + "alias": "SUCCESS Rx Total", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_rx_total" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + }, + { + "alias": "SUCCESS ALLOWABLE LOST PACKETS", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "C", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_can_be_lost" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "SUCCESS CRITERIA: TX Total = Rx Total + Tolerated Loss", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Packets Per Second", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_YARDSTICK}", + "fill": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 48 + }, + "id": 137, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": true, + "min": true, + "show": true, + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "MAX Line Rate", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.MAX_Rate" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + }, + { + "alias": "MIN Line Rate", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.MIN_Rate" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + }, + { + "alias": "Current Line Rate", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "C", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Test_Rate" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Line Rate", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 4, + "format": "short", + "label": "Line Rate", + "logBase": 1, + "max": "100", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "<h5 style=\"font-family:Verdana\"> <a style=\"color:#31A7D3\"><a style=\"font: 22px '#31A7D3'\"><center>Performance Stats</center> </a></h5>\n", + "editable": true, + "error": false, + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 56 + }, + "height": "40", + "id": 138, + "links": [], + "minSpan": 24, + "mode": "html", + "title": "", + "type": "text" + }, + { + "content": "<style=\"font-family:Verdana\"> <z style=\"font: 22px'\"><center>Packet size</center> </a>", + "gridPos": { + "h": 4, + "w": 2, + "x": 0, + "y": 59 + }, + "height": "30px", + "id": 15, + "links": [], + "mode": "html", + "title": "", + "type": "text" + }, + { + "content": "<h5 style=\"font-family:Verdana\"> <z style=\"font: 22px'\"><center>Theoretical Max Throughput (MPPS)</center> </a></h5>\n", + "gridPos": { + "h": 4, + "w": 2, + "x": 2, + "y": 59 + }, + "height": "30px", + "id": 16, + "links": [], + "mode": "html", + "title": "", + "type": "text" + }, + { + "content": "<h5 style=\"font-family:Verdana\"> <z style=\"font: 22px'\"><center>Tx Throughput (MPPS)</center> </a></h5>", + "gridPos": { + "h": 4, + "w": 2, + "x": 4, + "y": 59 + }, + "height": "30px", + "id": 17, + "links": [], + "mode": "html", + "title": "", + "type": "text" + }, + { + "content": "<h5 style=\"font-family:Verdana\"> <z style=\"font: 22px'\"><center>Rx Throughput (MPPS)</center></a></h5>", + "gridPos": { + "h": 4, + "w": 2, + "x": 6, + "y": 59 + }, + "height": "30px", + "id": 58, + "links": [], + "mode": "html", + "title": "", + "type": "text" + }, + { + "content": "<h5 style=\"font-family:Verdana\"> <z style=\"font: 22px'\"><center>Tot Sent </center></a></h5>", + "gridPos": { + "h": 4, + "w": 2, + "x": 8, + "y": 59 + }, + "height": "40px", + "id": 61, + "links": [], + "mode": "html", + "title": "", + "type": "text" + }, + { + "content": "<h5 style=\"font-family:Verdana\"> <z style=\"font: 22px'\"><center>Tot Received</center></a></h5>", + "gridPos": { + "h": 4, + "w": 2, + "x": 10, + "y": 59 + }, + "height": "30px", + "id": 62, + "links": [], + "mode": "html", + "title": "", + "type": "text" + }, + { + "content": "<h5 style=\"font-family:Verdana\"> <z style=\"font: 22px'\"><center>Tot Dropped</center></a></h5>", + "gridPos": { + "h": 4, + "w": 2, + "x": 12, + "y": 59 + }, + "height": "30px", + "id": 63, + "links": [], + "mode": "html", + "title": "", + "type": "text" + }, + { + "content": "<h5 style=\"font-family:Verdana\"> <z style=\"font: 22px'\"><center>Tolerated Loss</center></a></h5>\n", + "gridPos": { + "h": 4, + "w": 2, + "x": 14, + "y": 59 + }, + "height": "30px", + "id": 64, + "links": [], + "mode": "html", + "title": "", + "type": "text" + }, + { + "content": "<h5 style=\"font-family:Verdana\"> <z style=\"font: 22px'\"><center>Rx Throughput (Gbps)</center></a></h5>", + "gridPos": { + "h": 4, + "w": 2, + "x": 16, + "y": 59 + }, + "height": "30px", + "id": 124, + "links": [], + "mode": "html", + "title": "", + "type": "text" + }, + { + "content": "", + "gridPos": { + "h": 4, + "w": 6, + "x": 18, + "y": 59 + }, + "height": "30px", + "id": 125, + "links": [], + "mode": "html", + "title": "", + "transparent": false, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 0, + "y": 63 + }, + "height": "30px", + "hideTimeOverride": false, + "id": 18, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "alias": "Theoretical Max Throughput (Mpps)", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "hide": false, + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.PktSize\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE (\"tg__0.PktSize\" = 64) AND $timeFilter GROUP BY time($__interval) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.PktSize" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 2, + "y": 63 + }, + "height": "30px", + "hideTimeOverride": false, + "id": 140, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "alias": "Theoretical Max Throughput (Mpps)", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "hide": false, + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.theor_max_throughput\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE (\"tg__0.PktSize\" = 64 ) AND $timeFilter GROUP BY time($__interval) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.theor_max_throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 4, + "y": 63 + }, + "height": "30px", + "id": 20, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_TxThroughput\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 64 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 6, + "y": 63 + }, + "height": "30px", + "id": 69, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "last", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_RxThroughput\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 64 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "table", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 8, + "y": 63 + }, + "height": "30px", + "id": 70, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_tx_total\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 64 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 10, + "y": 63 + }, + "height": "30px", + "id": 71, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_rx_total\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 64 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 12, + "y": 63 + }, + "height": "30px", + "id": 72, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_drop_total\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 64 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 14, + "y": 63 + }, + "height": "30px", + "id": 73, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_can_be_lost\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 64 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 16, + "y": 63 + }, + "height": "30px", + "id": 127, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT mean(\"tg__0.Success_RxThroughput_gbps\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE (\"tg__0.PktSize\" = 64) AND $timeFilter GROUP BY time($__interval) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_RxThroughput_gbps" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "content": "", + "gridPos": { + "h": 3, + "w": 6, + "x": 18, + "y": 63 + }, + "height": "30px", + "id": 134, + "links": [], + "minSpan": 6, + "mode": "html", + "title": "", + "transparent": false, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 0, + "y": 66 + }, + "height": "30px", + "hideTimeOverride": false, + "id": 141, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "alias": "Theoretical Max Throughput (Mpps)", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "hide": false, + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.PktSize\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE (\"tg__0.PktSize\" = 128) AND $timeFilter GROUP BY time($__interval) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.PktSize" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 2, + "y": 66 + }, + "height": "30px", + "hideTimeOverride": false, + "id": 19, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "alias": "Max Throughput (Mpps)", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.theor_max_throughput\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE (\"tg__0.PktSize\" = 128 ) AND $timeFilter GROUP BY time($__interval) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.theor_max_throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 4, + "y": 66 + }, + "height": "30px", + "id": 142, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_TxThroughput\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 128 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 6, + "y": 66 + }, + "height": "30px", + "id": 143, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "last", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_RxThroughput\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 128 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "table", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 8, + "y": 66 + }, + "height": "30px", + "id": 144, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_tx_total\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 128 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 10, + "y": 66 + }, + "height": "30px", + "id": 145, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_rx_total\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 128 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 12, + "y": 66 + }, + "height": "30px", + "id": 146, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_drop_total\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 128 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 14, + "y": 66 + }, + "height": "30px", + "id": 147, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_can_be_lost\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 128 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 16, + "y": 66 + }, + "height": "30px", + "id": 148, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT mean(\"tg__0.Success_RxThroughput_gbps\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE (\"tg__0.PktSize\" = 128) AND $timeFilter GROUP BY time($__interval) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_RxThroughput_gbps" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "content": "", + "gridPos": { + "h": 3, + "w": 6, + "x": 18, + "y": 66 + }, + "height": "30px", + "id": 149, + "links": [], + "minSpan": 6, + "mode": "html", + "title": "", + "transparent": false, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 0, + "y": 69 + }, + "height": "30px", + "hideTimeOverride": false, + "id": 150, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "alias": "Theoretical Max Throughput (Mpps)", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "hide": false, + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.PktSize\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE (\"tg__0.PktSize\" = 256) AND $timeFilter GROUP BY time($__interval) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.PktSize" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 2, + "y": 69 + }, + "height": "30px", + "hideTimeOverride": false, + "id": 151, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "alias": "Theoretical Max Throughput (Mpps)", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "hide": false, + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.theor_max_throughput\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE (\"tg__0.PktSize\" = 256 ) AND $timeFilter GROUP BY time($__interval) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.theor_max_throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 4, + "y": 69 + }, + "height": "30px", + "id": 152, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_TxThroughput\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 256 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 6, + "y": 69 + }, + "height": "30px", + "id": 153, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "last", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_RxThroughput\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 256 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "table", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 8, + "y": 69 + }, + "height": "30px", + "id": 154, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_tx_total\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 256 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 10, + "y": 69 + }, + "height": "30px", + "id": 155, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_rx_total\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 256 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 12, + "y": 69 + }, + "height": "30px", + "id": 156, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_drop_total\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 256 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 14, + "y": 69 + }, + "height": "30px", + "id": 198, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_can_be_lost\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 256 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 16, + "y": 69 + }, + "height": "30px", + "id": 202, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT mean(\"tg__0.Success_RxThroughput_gbps\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE (\"tg__0.PktSize\" = 256) AND $timeFilter GROUP BY time($__interval) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_RxThroughput_gbps" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "content": "", + "gridPos": { + "h": 3, + "w": 6, + "x": 18, + "y": 69 + }, + "height": "30px", + "id": 159, + "links": [], + "minSpan": 6, + "mode": "html", + "title": "", + "transparent": false, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 0, + "y": 72 + }, + "height": "30px", + "hideTimeOverride": false, + "id": 166, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "alias": "Theoretical Max Throughput (Mpps)", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "hide": false, + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.PktSize\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE (\"tg__0.PktSize\" = 512) AND $timeFilter GROUP BY time($__interval) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.PktSize" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 2, + "y": 72 + }, + "height": "30px", + "hideTimeOverride": false, + "id": 171, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "alias": "Theoretical Max Throughput (Mpps)", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "hide": false, + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.theor_max_throughput\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE (\"tg__0.PktSize\" = 512) AND $timeFilter GROUP BY time($__interval) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.PktSize" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 4, + "y": 72 + }, + "height": "30px", + "id": 162, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_TxThroughput\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 512 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 6, + "y": 72 + }, + "height": "30px", + "id": 163, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "last", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_RxThroughput\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 512 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "table", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 8, + "y": 72 + }, + "height": "30px", + "id": 164, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_tx_total\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 512 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 10, + "y": 72 + }, + "height": "30px", + "id": 165, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_rx_total\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 512 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 12, + "y": 72 + }, + "height": "30px", + "id": 193, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_drop_total\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 512 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 14, + "y": 72 + }, + "height": "30px", + "id": 157, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_can_be_lost\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 512 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 16, + "y": 72 + }, + "height": "30px", + "id": 200, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT mean(\"tg__0.Success_RxThroughput_gbps\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE (\"tg__0.PktSize\" = 512) AND $timeFilter GROUP BY time($__interval) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_RxThroughput_gbps" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "content": "", + "gridPos": { + "h": 3, + "w": 6, + "x": 18, + "y": 72 + }, + "height": "30px", + "id": 210, + "links": [], + "minSpan": 6, + "mode": "html", + "title": "", + "transparent": false, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 0, + "y": 75 + }, + "height": "30px", + "hideTimeOverride": false, + "id": 160, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "alias": "Theoretical Max Throughput (Mpps)", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "hide": false, + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.PktSize\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE (\"tg__0.PktSize\" = 1024) AND $timeFilter GROUP BY time($__interval) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.PktSize" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 2, + "y": 75 + }, + "height": "30px", + "hideTimeOverride": false, + "id": 170, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "alias": "Theoretical Max Throughput (Mpps)", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "hide": false, + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(tg__0.theor_max_throughput) FROM \"tc_prox_baremetal_l3fwd-4\" WHERE (\"tg__0.PktSize\" = 1024) AND $timeFilter GROUP BY time($__interval) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.PktSize" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 4, + "y": 75 + }, + "height": "30px", + "id": 174, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_TxThroughput\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 1024 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 6, + "y": 75 + }, + "height": "30px", + "id": 178, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "last", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_RxThroughput\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 1024 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "table", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 8, + "y": 75 + }, + "height": "30px", + "id": 182, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_tx_total\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 1024 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 10, + "y": 75 + }, + "height": "30px", + "id": 185, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_rx_total\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 1024 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 12, + "y": 75 + }, + "height": "30px", + "id": 191, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_drop_total\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 1024 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 14, + "y": 75 + }, + "height": "30px", + "id": 195, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_can_be_lost\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 1024 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 16, + "y": 75 + }, + "height": "30px", + "id": 203, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT mean(\"tg__0.Success_RxThroughput_gbps\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE (\"tg__0.PktSize\" = 1024) AND $timeFilter GROUP BY time($__interval) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_RxThroughput_gbps" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "content": "", + "gridPos": { + "h": 3, + "w": 6, + "x": 18, + "y": 75 + }, + "height": "30px", + "id": 209, + "links": [], + "minSpan": 6, + "mode": "html", + "title": "", + "transparent": false, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 0, + "y": 78 + }, + "height": "30px", + "hideTimeOverride": false, + "id": 168, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "alias": "Theoretical Max Throughput (Mpps)", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "hide": false, + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.PktSize\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE (\"tg__0.PktSize\" = 1280) AND $timeFilter GROUP BY time($__interval) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.PktSize" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 2, + "y": 78 + }, + "height": "30px", + "hideTimeOverride": false, + "id": 172, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "alias": "Theoretical Max Throughput (Mpps)", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "hide": false, + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.theor_max_throughput\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE (\"tg__0.PktSize\" = 1280 ) AND $timeFilter GROUP BY time($__interval) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.theor_max_throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 4, + "y": 78 + }, + "height": "30px", + "id": 175, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_TxThroughput\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 1280 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 6, + "y": 78 + }, + "height": "30px", + "id": 179, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "last", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_RxThroughput\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 1280 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "table", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 8, + "y": 78 + }, + "height": "30px", + "id": 183, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_tx_total\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 1280 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 10, + "y": 78 + }, + "height": "30px", + "id": 186, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_rx_total\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 1280 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 12, + "y": 78 + }, + "height": "30px", + "id": 190, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_drop_total\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 1280 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 14, + "y": 78 + }, + "height": "30px", + "id": 196, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_can_be_lost\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 1280 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 16, + "y": 78 + }, + "height": "30px", + "id": 204, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT mean(\"tg__0.Success_RxThroughput_gbps\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE (\"tg__0.PktSize\" = 1280) AND $timeFilter GROUP BY time($__interval) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_RxThroughput_gbps" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "content": "", + "gridPos": { + "h": 3, + "w": 6, + "x": 18, + "y": 78 + }, + "height": "30px", + "id": 208, + "links": [], + "minSpan": 6, + "mode": "html", + "title": "", + "transparent": false, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 0, + "y": 81 + }, + "height": "30px", + "hideTimeOverride": false, + "id": 167, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "alias": "Theoretical Max Throughput (Mpps)", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "hide": false, + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.PktSize\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE (\"tg__0.PktSize\" = 1518) AND $timeFilter GROUP BY time($__interval) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.PktSize" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 2, + "y": 81 + }, + "height": "30px", + "hideTimeOverride": false, + "id": 173, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "alias": "Theoretical Max Throughput (Mpps)", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "hide": false, + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.theor_max_throughput\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE (\"tg__0.PktSize\" = 1518 ) AND $timeFilter GROUP BY time($__interval) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.theor_max_throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 4, + "y": 81 + }, + "height": "30px", + "id": 176, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_TxThroughput\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 1518 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 6, + "y": 81 + }, + "height": "30px", + "id": 180, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "last", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_RxThroughput\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 1518 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "table", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 8, + "y": 81 + }, + "height": "30px", + "id": 187, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_tx_total\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 1518 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 10, + "y": 81 + }, + "height": "30px", + "id": 184, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_rx_total\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 1518 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 12, + "y": 81 + }, + "height": "30px", + "id": 194, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_drop_total\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 1518 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 14, + "y": 81 + }, + "height": "30px", + "id": 197, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_can_be_lost\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 1518 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 16, + "y": 81 + }, + "height": "30px", + "id": 158, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT mean(\"tg__0.Success_RxThroughput_gbps\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE (\"tg__0.PktSize\" = 1518) AND $timeFilter GROUP BY time($__interval) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_RxThroughput_gbps" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "content": "", + "gridPos": { + "h": 3, + "w": 6, + "x": 18, + "y": 81 + }, + "height": "30px", + "id": 206, + "links": [], + "minSpan": 6, + "mode": "html", + "title": "", + "transparent": false, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 0, + "y": 84 + }, + "height": "30px", + "hideTimeOverride": false, + "id": 169, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "alias": "Theoretical Max Throughput (Mpps)", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "hide": false, + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.PktSize\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE (\"tg__0.PktSize\" = 2048) AND $timeFilter GROUP BY time($__interval) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.PktSize" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 2, + "y": 84 + }, + "height": "30px", + "hideTimeOverride": false, + "id": 161, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "alias": "Theoretical Max Throughput (Mpps)", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "hide": false, + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.theor_max_throughput\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE (\"tg__0.PktSize\" = 2048 ) AND $timeFilter GROUP BY time($__interval) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.theor_max_throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 4, + "y": 84 + }, + "height": "30px", + "id": 177, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_TxThroughput\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 2048 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 6, + "y": 84 + }, + "height": "30px", + "id": 181, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "last", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_RxThroughput\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 2048 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "table", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 8, + "y": 84 + }, + "height": "30px", + "id": 188, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_tx_total\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 2048 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 10, + "y": 84 + }, + "height": "30px", + "id": 189, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_rx_total\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 2048 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 12, + "y": 84 + }, + "height": "30px", + "id": 192, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_drop_total\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 2048 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 14, + "y": 84 + }, + "height": "30px", + "id": 199, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_can_be_lost\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE \"tg__0.Success_PktSize\" = 2048 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 2, + "x": 16, + "y": 84 + }, + "height": "30px", + "id": 205, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT mean(\"tg__0.Success_RxThroughput_gbps\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE (\"tg__0.PktSize\" = 2048) AND $timeFilter GROUP BY time($__interval) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_RxThroughput_gbps" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "content": "", + "gridPos": { + "h": 3, + "w": 6, + "x": 18, + "y": 84 + }, + "height": "30px", + "id": 207, + "links": [], + "minSpan": 6, + "mode": "html", + "title": "", + "transparent": false, + "type": "text" + }, + { + "content": "<h5 style=\"font-family:Verdana\"> <a style=\"color:#31A7D3\"><a style=\"font: 22px '#31A7D3'\"><center>Latency</center> </a></h5>", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 87 + }, + "height": "40", + "id": 41, + "links": [], + "mode": "html", + "title": "", + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_YARDSTICK}", + "fill": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 90 + }, + "height": "300px", + "id": 47, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": true, + "min": true, + "show": true, + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "xe0 Latency Avg", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.LatencyAvg.5" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + }, + { + "alias": "xe0 Latency Max", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.LatencyMax.5" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "xe0 Latency", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "usec", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_YARDSTICK}", + "fill": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 90 + }, + "height": "300px", + "id": 48, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": true, + "min": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "xe1 Latency Avg", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.LatencyAvg.5" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + }, + { + "alias": "xe1 Latency Max", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.LatencyAvg.6" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "xe1 Latency", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "usec", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_YARDSTICK}", + "fill": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 98 + }, + "height": "300px", + "id": 49, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": true, + "min": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "xe2 Latency Avg", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.LatencyAvg.7" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + }, + { + "alias": "xe2 Latency Max", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.LatencyAvg.7" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "xe2 Latency", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "usec", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_YARDSTICK}", + "fill": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 98 + }, + "height": "300px", + "id": 211, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": true, + "min": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "xe2 Latency Avg", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.LatencyAvg.8" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + }, + { + "alias": "xe2 Latency Max", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.LatencyMax.8" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "xe2 Latency", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "usec", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "<h5 style=\"font-family:Verdana\"> <a style=\"color:#31A7D3\"><a style=\"font: 22px '#31A7D3'\"><center>SUT CPU Utilization</center> </a></h5>", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 106 + }, + "height": "40px", + "id": 51, + "links": [], + "mode": "html", + "title": "", + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_YARDSTICK}", + "decimals": 5, + "fill": 1, + "gridPos": { + "h": 11, + "w": 12, + "x": 0, + "y": 109 + }, + "height": "900px", + "id": 53, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "sort": "avg", + "sortDesc": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "CPU 0 - Master", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "vnf__0.collect_stats.core.cpu.0.percent-user" + ], + "type": "field" + }, + { + "params": [], + "type": "distinct" + } + ] + ], + "tags": [] + }, + { + "alias": "CPU 1 - RX:p0 - Routing - TX:p0,p1", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "vnf__0.collect_stats.core.cpu.1.percent-user" + ], + "type": "field" + }, + { + "params": [], + "type": "distinct" + } + ] + ], + "tags": [] + }, + { + "alias": "CPU 2 - RX:p1 - Routing - TX:p0,p1", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "C", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "vnf__0.collect_stats.core.cpu.2.percent-user" + ], + "type": "field" + }, + { + "params": [], + "type": "distinct" + } + ] + ], + "tags": [] + }, + { + "alias": "CPU 3 - RX:p2 - Routing - TX:p2,p3", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT distinct(\"vnf__0.collect_stats.core.cpu.3.percent-user\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE $timeFilter GROUP BY time($__interval) fill(none)", + "rawQuery": false, + "refId": "D", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "vnf__0.collect_stats.core.cpu.3.percent-user" + ], + "type": "field" + }, + { + "params": [], + "type": "distinct" + } + ] + ], + "tags": [] + }, + { + "alias": "CPU 4 - RX:p3 - Routing - TX:p2,p3", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT distinct(\"vnf__0.collect_stats.core.cpu.4.percent-user\") FROM \"tc_prox_baremetal_l3fwd-4\" WHERE $timeFilter GROUP BY time($__interval) fill(none)", + "rawQuery": false, + "refId": "E", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "vnf__0.collect_stats.core.cpu.4.percent-user" + ], + "type": "field" + }, + { + "params": [], + "type": "distinct" + } + ] + ], + "tags": [] + }, + { + "alias": "CPU 5", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "hide": true, + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "F", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "vnf__0.collect_stats.core.cpu.5.percent-user" + ], + "type": "field" + }, + { + "params": [], + "type": "distinct" + } + ] + ], + "tags": [] + }, + { + "alias": "CPU 6", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "hide": true, + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "G", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "vnf__0.collect_stats.core.cpu.6.percent-user" + ], + "type": "field" + }, + { + "params": [], + "type": "distinct" + } + ] + ], + "tags": [] + }, + { + "alias": "CPU 7", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "hide": true, + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "H", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "vnf__0.collect_stats.core.cpu.7.percent-user" + ], + "type": "field" + }, + { + "params": [], + "type": "distinct" + } + ] + ], + "tags": [] + }, + { + "alias": "CPU 8", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "hide": true, + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "I", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "vnf__0.collect_stats.core.cpu.8.percent-user" + ], + "type": "field" + }, + { + "params": [], + "type": "distinct" + } + ] + ], + "tags": [] + }, + { + "alias": "CPU 9", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "hide": true, + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "J", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "vnf__0.collect_stats.core.cpu.9.percent-user" + ], + "type": "field" + }, + { + "params": [], + "type": "distinct" + } + ] + ], + "tags": [] + }, + { + "alias": "CPU 10", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "hide": true, + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "K", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "vnf__0.collect_stats.core.cpu.10.percent-user" + ], + "type": "field" + }, + { + "params": [], + "type": "distinct" + } + ] + ], + "tags": [] + }, + { + "alias": "CPU 11", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "hide": true, + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "L", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "vnf__0.collect_stats.core.cpu.11.percent-user" + ], + "type": "field" + }, + { + "params": [], + "type": "distinct" + } + ] + ], + "tags": [] + }, + { + "alias": "CPU 12", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "hide": true, + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "M", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "vnf__0.collect_stats.core.cpu.12.percent-user" + ], + "type": "field" + }, + { + "params": [], + "type": "distinct" + } + ] + ], + "tags": [] + }, + { + "alias": "CPU 13", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "hide": true, + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "N", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "vnf__0.collect_stats.core.cpu.13.percent-user" + ], + "type": "field" + }, + { + "params": [], + "type": "distinct" + } + ] + ], + "tags": [] + }, + { + "alias": "CPU 14", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "hide": true, + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "O", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "vnf__0.collect_stats.core.cpu.14.percent-user" + ], + "type": "field" + }, + { + "params": [], + "type": "distinct" + } + ] + ], + "tags": [] + }, + { + "alias": "CPU 15", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "hide": true, + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "P", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "vnf__0.collect_stats.core.cpu.15.percent-user" + ], + "type": "field" + }, + { + "params": [], + "type": "distinct" + } + ] + ], + "tags": [] + }, + { + "alias": "CPU 16", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "hide": true, + "measurement": "tc_prox_baremetal_l3fwd-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "Q", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "vnf__0.collect_stats.core.cpu.17.percent-user" + ], + "type": "field" + }, + { + "params": [], + "type": "distinct" + } + ] + ], + "tags": [] + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "SUT CPU Utilization", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percent", + "label": "% Utilization", + "logBase": 1, + "max": "100", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "", + "gridPos": { + "h": 3, + "w": 6, + "x": 0, + "y": 120 + }, + "height": "30px", + "id": 133, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + } + ], + "refresh": "5s", + "schemaVersion": 16, + "style": "dark", + "tags": [ + "yardstick", + "NSB", + "Prox", + "l3fwd", + "4Port", + "BM" + ], + "templating": { + "list": [] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "Prox_BM_l3fwd-4Port", + "uid": "G-hksJHmz", + "version": 13 +}
\ No newline at end of file diff --git a/dashboard/Prox_BM_vPE-4Port-1507804058631.json b/dashboard/Prox_BM_vPE-4Port-1507804058631.json deleted file mode 100644 index 52afcaed3..000000000 --- a/dashboard/Prox_BM_vPE-4Port-1507804058631.json +++ /dev/null @@ -1,1163 +0,0 @@ -{ - "__inputs": [ - { - "name": "DS_YARDSTICK", - "label": "yardstick", - "description": "", - "type": "datasource", - "pluginId": "influxdb", - "pluginName": "InfluxDB" - } - ], - "__requires": [ - { - "type": "grafana", - "id": "grafana", - "name": "Grafana", - "version": "4.4.3" - }, - { - "type": "panel", - "id": "graph", - "name": "Graph", - "version": "" - }, - { - "type": "datasource", - "id": "influxdb", - "name": "InfluxDB", - "version": "1.0.0" - }, - { - "type": "panel", - "id": "text", - "name": "Text", - "version": "" - } - ], - "annotations": { - "list": [] - }, - "editable": true, - "gnetId": null, - "graphTooltip": 0, - "hideControls": false, - "id": null, - "links": [], - "refresh": false, - "rows": [ - { - "collapse": false, - "height": "100px", - "panels": [ - { - "content": "<h5 style=\"font-family:Verdana\"> <a style=\"color:#31A7D3\"><a style=\"font: 32px '#31A7D3'\"><center>OPNFV_Yardstick_NSB_PROX_BM_vPE_4Port_Test</center> </a></h5>\n<center>\n<p>The vPE handles packet processing, routing, QinQ encapsulation, flows, ACL rules, adds/removes MPLS tags and performs QoS </p>\n<p>The KPI is the number of packets per second for a specified packet size (min packet size is 68 byte) with an accepted minimal packet loss</p>\n</center>", - "editable": true, - "error": false, - "id": 3, - "links": [], - "mode": "html", - "span": 12, - "title": "", - "type": "text" - }, - { - "content": "<h5 style=\"font-family:Verdana\"> <a style=\"color:#31A7D3\"><a style=\"font: 22px '#31A7D3'\"><center>Prox vPE VNF stats</center> </a></h5>\n", - "editable": true, - "error": false, - "height": "40", - "id": 7, - "links": [], - "mode": "html", - "span": 12, - "title": "", - "type": "text" - } - ], - "repeat": null, - "repeatIteration": null, - "repeatRowId": null, - "showTitle": false, - "title": "Row", - "titleSize": "h6" - }, - { - "collapse": false, - "height": "300px", - "panels": [ - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "${DS_YARDSTICK}", - "editable": true, - "error": false, - "fill": 1, - "grid": {}, - "height": "300", - "id": 4, - "legend": { - "alignAsTable": true, - "avg": true, - "current": false, - "max": true, - "min": true, - "rightSide": false, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 2, - "links": [], - "nullPointMode": "connected", - "percentage": false, - "pointradius": 1, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "span": 12, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "VNF packets Forward", - "dsType": "influxdb", - "groupBy": [ - { - "params": [ - "$interval" - ], - "type": "time" - }, - { - "params": [ - "null" - ], - "type": "fill" - } - ], - "measurement": "tc_prox_baremetal_vpe-4", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "vnf__0.packets_fwd" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [] - }, - { - "alias": "VNF packets in", - "dsType": "influxdb", - "groupBy": [ - { - "params": [ - "$interval" - ], - "type": "time" - }, - { - "params": [ - "null" - ], - "type": "fill" - } - ], - "measurement": "tc_prox_baremetal_vpe-4", - "orderByTime": "ASC", - "policy": "default", - "refId": "C", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "vnf__0.packets_in" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [] - }, - { - "alias": "VNF packets dropped", - "dsType": "influxdb", - "groupBy": [ - { - "params": [ - "$interval" - ], - "type": "time" - }, - { - "params": [ - "null" - ], - "type": "fill" - } - ], - "measurement": "tc_prox_baremetal_vpe-4", - "orderByTime": "ASC", - "policy": "default", - "refId": "B", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "vnf__0.packets_dropped" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [] - } - ], - "thresholds": [ - { - "colorMode": "custom", - "fill": true, - "fillColor": "rgba(216, 200, 27, 0.27)", - "op": "gt", - "value": 2 - }, - { - "colorMode": "custom", - "fill": true, - "fillColor": "rgba(234, 112, 112, 0.22)", - "op": "gt", - "value": 2 - } - ], - "timeFrom": null, - "timeShift": null, - "title": "vPE VNF stats", - "tooltip": { - "msResolution": true, - "shared": true, - "sort": 0, - "value_type": "cumulative" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": "Packets", - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "content": "<h5 style=\"font-family:Verdana\"> <a style=\"color:#31A7D3\"><a style=\"font: 22px '#31A7D3'\"><center>Prox vPE Traffic Gen stats</center> </a></h5>\n", - "editable": true, - "error": false, - "height": "40", - "id": 8, - "links": [], - "mode": "html", - "span": 12, - "title": "", - "type": "text" - } - ], - "repeat": null, - "repeatIteration": null, - "repeatRowId": null, - "showTitle": false, - "title": "New row", - "titleSize": "h6" - }, - { - "collapse": false, - "height": "300px", - "panels": [ - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "${DS_YARDSTICK}", - "editable": true, - "error": false, - "fill": 1, - "grid": {}, - "id": 6, - "legend": { - "alignAsTable": true, - "avg": true, - "current": false, - "max": true, - "min": true, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 2, - "links": [], - "nullPointMode": "connected", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "span": 6, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "TG xe-0 Out packets", - "dsType": "influxdb", - "groupBy": [ - { - "params": [ - "$interval" - ], - "type": "time" - }, - { - "params": [ - "null" - ], - "type": "fill" - } - ], - "measurement": "tc_prox_baremetal_vpe-4", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "tg__0.xe0.out_packets" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [] - }, - { - "alias": "TG xe-1 Out packets", - "dsType": "influxdb", - "groupBy": [ - { - "params": [ - "$interval" - ], - "type": "time" - }, - { - "params": [ - "null" - ], - "type": "fill" - } - ], - "measurement": "tc_prox_baremetal_vpe-4", - "orderByTime": "ASC", - "policy": "default", - "refId": "B", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "tg__0.xe1.out_packets" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [] - }, - { - "alias": "TG xe-2 Out packets", - "dsType": "influxdb", - "groupBy": [ - { - "params": [ - "$interval" - ], - "type": "time" - }, - { - "params": [ - "null" - ], - "type": "fill" - } - ], - "measurement": "tc_prox_baremetal_vpe-4", - "orderByTime": "ASC", - "policy": "default", - "refId": "C", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "tg__0.xe2.out_packets" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [] - }, - { - "alias": "TG xe-3 Out packets", - "dsType": "influxdb", - "groupBy": [ - { - "params": [ - "$interval" - ], - "type": "time" - }, - { - "params": [ - "null" - ], - "type": "fill" - } - ], - "measurement": "tc_prox_baremetal_vpe-4", - "orderByTime": "ASC", - "policy": "default", - "refId": "D", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "tg__0.xe3.out_packets" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [] - } - ], - "thresholds": [ - { - "colorMode": "custom", - "fill": true, - "fillColor": "rgba(216, 200, 27, 0.27)", - "op": "gt", - "value": 2 - }, - { - "colorMode": "custom", - "fill": true, - "fillColor": "rgba(234, 112, 112, 0.22)", - "op": "gt", - "value": 2 - } - ], - "timeFrom": null, - "timeShift": null, - "title": "TG Port Stats: Out packets", - "tooltip": { - "msResolution": true, - "shared": true, - "sort": 0, - "value_type": "cumulative" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": "Packets ", - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "${DS_YARDSTICK}", - "editable": true, - "error": false, - "fill": 1, - "grid": {}, - "id": 9, - "legend": { - "alignAsTable": true, - "avg": true, - "current": false, - "max": true, - "min": true, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 2, - "links": [], - "nullPointMode": "connected", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "span": 6, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "TG xe-0 in packets", - "dsType": "influxdb", - "groupBy": [ - { - "params": [ - "$interval" - ], - "type": "time" - }, - { - "params": [ - "null" - ], - "type": "fill" - } - ], - "measurement": "tc_prox_baremetal_vpe-4", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "tg__0.xe0.in_packets" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [] - }, - { - "alias": "TG xe-1 in packets", - "dsType": "influxdb", - "groupBy": [ - { - "params": [ - "$interval" - ], - "type": "time" - }, - { - "params": [ - "null" - ], - "type": "fill" - } - ], - "measurement": "tc_prox_baremetal_vpe-4", - "orderByTime": "ASC", - "policy": "default", - "refId": "B", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "tg__0.xe1.in_packets" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [] - }, - { - "alias": "TG xe-2 in packets", - "dsType": "influxdb", - "groupBy": [ - { - "params": [ - "$interval" - ], - "type": "time" - }, - { - "params": [ - "null" - ], - "type": "fill" - } - ], - "measurement": "tc_prox_baremetal_vpe-4", - "orderByTime": "ASC", - "policy": "default", - "refId": "C", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "tg__0.xe2.in_packets" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [] - }, - { - "alias": "TG xe-3 in packets", - "dsType": "influxdb", - "groupBy": [ - { - "params": [ - "$interval" - ], - "type": "time" - }, - { - "params": [ - "null" - ], - "type": "fill" - } - ], - "measurement": "tc_prox_baremetal_vpe-4", - "orderByTime": "ASC", - "policy": "default", - "refId": "D", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "tg__0.xe3.in_packets" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [] - } - ], - "thresholds": [ - { - "colorMode": "custom", - "fill": true, - "fillColor": "rgba(216, 200, 27, 0.27)", - "op": "gt", - "value": 2 - }, - { - "colorMode": "custom", - "fill": true, - "fillColor": "rgba(234, 112, 112, 0.22)", - "op": "gt", - "value": 2 - } - ], - "timeFrom": null, - "timeShift": null, - "title": "TG Port Stats: In packets", - "tooltip": { - "msResolution": true, - "shared": true, - "sort": 0, - "value_type": "cumulative" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": "Packets ", - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - } - ], - "repeat": null, - "repeatIteration": null, - "repeatRowId": null, - "showTitle": false, - "title": "New row", - "titleSize": "h6" - }, - { - "collapse": false, - "height": "250px", - "panels": [ - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "${DS_YARDSTICK}", - "editable": true, - "error": false, - "fill": 1, - "grid": {}, - "id": 2, - "legend": { - "alignAsTable": true, - "avg": true, - "current": false, - "max": true, - "min": true, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 2, - "links": [], - "nullPointMode": "connected", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "span": 6, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "TX Throughput", - "dsType": "influxdb", - "groupBy": [ - { - "params": [ - "$interval" - ], - "type": "time" - }, - { - "params": [ - "null" - ], - "type": "fill" - } - ], - "measurement": "tc_prox_baremetal_vpe-4", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "tg__0.TxThroughput" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [] - }, - { - "alias": "RX Throughput", - "dsType": "influxdb", - "groupBy": [ - { - "params": [ - "$interval" - ], - "type": "time" - }, - { - "params": [ - "null" - ], - "type": "fill" - } - ], - "measurement": "tc_prox_baremetal_vpe-4", - "orderByTime": "ASC", - "policy": "default", - "refId": "B", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "tg__0.RxThroughput" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [] - } - ], - "thresholds": [ - { - "colorMode": "custom", - "fill": true, - "fillColor": "rgba(216, 200, 27, 0.27)", - "op": "gt", - "value": 2 - }, - { - "colorMode": "custom", - "fill": true, - "fillColor": "rgba(234, 112, 112, 0.22)", - "op": "gt", - "value": 2 - } - ], - "timeFrom": null, - "timeShift": null, - "title": "TG Tx vs Rx Throughput", - "tooltip": { - "msResolution": true, - "shared": true, - "sort": 0, - "value_type": "cumulative" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": "Throughput in MPPS", - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "${DS_YARDSTICK}", - "editable": true, - "error": false, - "fill": 1, - "grid": {}, - "id": 5, - "legend": { - "alignAsTable": true, - "avg": true, - "current": false, - "max": true, - "min": true, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 2, - "links": [], - "nullPointMode": "connected", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "span": 6, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "Packet Size", - "dsType": "influxdb", - "groupBy": [ - { - "params": [ - "$interval" - ], - "type": "time" - }, - { - "params": [ - "null" - ], - "type": "fill" - } - ], - "measurement": "tc_prox_baremetal_vpe-4", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "tg__0.PktSize" - ], - "type": "field" - }, - { - "params": [], - "type": "mean" - } - ] - ], - "tags": [] - } - ], - "thresholds": [ - { - "colorMode": "custom", - "fill": true, - "fillColor": "rgba(216, 200, 27, 0.27)", - "op": "gt", - "value": 2 - }, - { - "colorMode": "custom", - "fill": true, - "fillColor": "rgba(234, 112, 112, 0.22)", - "op": "gt", - "value": 2 - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Packet size", - "tooltip": { - "msResolution": true, - "shared": true, - "sort": 0, - "value_type": "cumulative" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "bytes", - "label": "Packet Size", - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - } - ], - "repeat": null, - "repeatIteration": null, - "repeatRowId": null, - "showTitle": false, - "title": "New row", - "titleSize": "h6" - }, - { - "collapse": false, - "height": "250px", - "panels": [], - "repeat": null, - "repeatIteration": null, - "repeatRowId": null, - "showTitle": false, - "title": "New row", - "titleSize": "h6" - } - ], - "schemaVersion": 14, - "style": "dark", - "tags": [ - "yardstick", - "NSB", - "Prox", - "4Port", - "BM", - "vPE" - ], - "templating": { - "list": [] - }, - "time": { - "from": "2017-10-09T11:05:30.701Z", - "to": "2017-10-09T11:11:21.952Z" - }, - "timepicker": { - "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ], - "time_options": [ - "5m", - "15m", - "1h", - "6h", - "12h", - "24h", - "2d", - "7d", - "30d" - ] - }, - "timezone": "browser", - "title": "Prox_BM_vPE-4Port", - "version": 10 -}
\ No newline at end of file diff --git a/dashboard/Prox_BM_vpe-4Port-1529345833067.json b/dashboard/Prox_BM_vpe-4Port-1529345833067.json new file mode 100644 index 000000000..6ef11e4f8 --- /dev/null +++ b/dashboard/Prox_BM_vpe-4Port-1529345833067.json @@ -0,0 +1,10152 @@ +{ + "__inputs": [ + { + "name": "DS_YARDSTICK", + "label": "yardstick", + "description": "", + "type": "datasource", + "pluginId": "influxdb", + "pluginName": "InfluxDB" + } + ], + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "4.4.3" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph", + "version": "" + }, + { + "type": "datasource", + "id": "influxdb", + "name": "InfluxDB", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "singlestat", + "name": "Singlestat", + "version": "" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "" + } + ], + "annotations": { + "list": [] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "hideControls": false, + "id": null, + "links": [], + "refresh": false, + "rows": [ + { + "collapse": false, + "height": "100px", + "panels": [ + { + "content": "<h5 style=\"font-family:Verdana\"> <a style=\"color:#31A7D3\"><a style=\"font: 32px '#31A7D3'\"><center>OPNFV_Yardstick_NSB_PROX_BM_vPE_4Port_Test</center> </a></h5>\n<center>\n<p>The application does Port forwarding without touching packets. It will take packets in from one port and forward them unmodified to another port </p>\n<p>The KPI is the number of packets per second for a specified packet size with an accepted minimal packet loss </p>\n</center>", + "editable": true, + "error": false, + "id": 3, + "links": [], + "mode": "html", + "span": 12, + "title": "", + "type": "text" + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Row", + "titleSize": "h6" + }, + { + "collapse": false, + "height": 362, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "fill": 1, + "id": 123, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": true, + "min": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "span": 12, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "Cumulative Packets Sents", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "vnf__0.packets_fwd" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": [ + { + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(216, 200, 27, 0.27)", + "line": true, + "lineColor": "rgba(0, 0, 0, 0)", + "op": "gt", + "value": 0 + }, + { + "colorMode": "custom", + "fill": true, + "fillColor": "rgb(234, 112, 112, 0.22)", + "line": true, + "lineColor": "rgba(0, 0, 0, 0.01)", + "op": "gt", + "value": 0 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Cumulative Load Sent by Generator", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Packets Per Second", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Cumulative Load Sent by Generator", + "titleSize": "h6" + }, + { + "collapse": false, + "height": 331, + "panels": [ + { + "content": "<h5 style=\"font-family:Verdana\"> <a style=\"color:#31A7D3\"><a style=\"font: 22px '#31A7D3'\"><center>Throughput</center> </a></h5>\n", + "editable": true, + "error": false, + "height": "40", + "id": 7, + "links": [], + "minSpan": 12, + "mode": "html", + "span": 12, + "title": "", + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "editable": true, + "error": false, + "fill": 1, + "grid": {}, + "id": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": true, + "min": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "span": 6, + "stack": false, + "steppedLine": true, + "targets": [ + { + "alias": "Load Requested to Generator", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.RequestedTxThroughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + }, + { + "alias": "Load Generated (by the Generator)", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.TxThroughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + }, + { + "alias": "Load Received (by the Generator)", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "hide": false, + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.RxThroughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": [ + { + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(216, 200, 27, 0.27)", + "op": "gt", + "value": 0 + }, + { + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(234, 112, 112, 0.22)", + "op": "gt", + "value": 0 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Generator stats", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "transparent": false, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Million Packets Per Second", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_YARDSTICK}", + "editable": true, + "error": false, + "fill": 1, + "grid": {}, + "id": 5, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": true, + "min": true, + "show": true, + "sort": "min", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "span": 6, + "stack": false, + "steppedLine": true, + "targets": [ + { + "alias": "Packet Size", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.PktSize" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + }, + { + "alias": "MAX Line Rate", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.MAX_Rate" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + }, + { + "alias": "MIN Line Rate", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "C", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.MIN_Rate" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + }, + { + "alias": "Test Rate", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "D", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Test_Rate" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": [ + { + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(216, 200, 27, 0.27)", + "op": "gt", + "value": 0 + }, + { + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(234, 112, 112, 0.22)", + "op": "gt", + "value": 0 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Packet size & Percent of Line Rate", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "none", + "label": "Packet Size (Bytes)", + "logBase": 2, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "New row", + "titleSize": "h6" + }, + { + "collapse": false, + "height": 288, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "editable": true, + "error": false, + "fill": 1, + "grid": {}, + "height": "300", + "id": 4, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 1, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "span": 6, + "stack": false, + "steppedLine": true, + "targets": [ + { + "alias": "SUT Packets Received", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "C", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "vnf__0.curr_packets_in" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + }, + { + "params": [ + " / 1000000" + ], + "type": "math" + } + ] + ], + "tags": [] + } + ], + "thresholds": [ + { + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(216, 200, 27, 0.27)", + "op": "gt", + "value": 0 + }, + { + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(234, 112, 112, 0.22)", + "op": "gt", + "value": 0 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "SUT Stats - Load Received By SUT", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Million Packets per Second", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "editable": true, + "error": false, + "fill": 1, + "grid": {}, + "height": "300", + "id": 39, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 1, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "span": 6, + "stack": false, + "steppedLine": true, + "targets": [ + { + "alias": "SUT Packets Sent", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "vnf__0.curr_packets_fwd" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + }, + { + "params": [ + " / 1000000" + ], + "type": "math" + } + ] + ], + "tags": [] + } + ], + "thresholds": [ + { + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(216, 200, 27, 0.27)", + "op": "gt", + "value": 0 + }, + { + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(234, 112, 112, 0.22)", + "op": "gt", + "value": 0 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "SUT Stats - Load Forwarded By SUT", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Million Packets per Second", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "New row", + "titleSize": "h6" + }, + { + "collapse": false, + "height": 289, + "panels": [ + { + "content": "<h5 style=\"font-family:Verdana\"> <a style=\"color:#31A7D3\"><a style=\"font: 22px '#31A7D3'\"><center>Prox VPE Traffic Gen stats</center> </a></h5>\n", + "editable": true, + "error": false, + "height": "40", + "id": 8, + "links": [], + "minSpan": 12, + "mode": "html", + "span": 12, + "title": "", + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "editable": true, + "error": false, + "fill": 1, + "grid": {}, + "id": 43, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": true, + "min": true, + "show": true, + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "span": 6, + "stack": false, + "steppedLine": true, + "targets": [ + { + "alias": "TG xe-0 Out packets", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.xe0.out_packets" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + }, + { + "alias": "TG xe-1 Out packets", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.xe1.out_packets" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + }, + { + "alias": "TG xe-2 Out packets", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "C", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.xe2.out_packets" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + }, + { + "alias": "TG xe-3 Out packets", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "D", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.xe3.out_packets" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": [ + { + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(216, 200, 27, 0.27)", + "op": "gt", + "value": 0 + }, + { + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(234, 112, 112, 0.22)", + "op": "gt", + "value": 0 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Packets Sent by Generator", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Packets ", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_YARDSTICK}", + "editable": true, + "error": false, + "fill": 1, + "grid": {}, + "id": 9, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": true, + "min": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "span": 6, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "TG xe-0 in packets", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.xe0.in_packets" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + }, + { + "alias": "TG xe-1 in packets", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.xe1.in_packets" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + }, + { + "alias": "TG xe-2 in packets", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "C", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.xe2.in_packets" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + }, + { + "alias": "TG xe-3 in packets", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "D", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.xe3.in_packets" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": [ + { + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(216, 200, 27, 0.27)", + "op": "gt", + "value": 0 + }, + { + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(234, 112, 112, 0.22)", + "op": "gt", + "value": 0 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Packets Received by Generator", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Packets Per Second", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "New row", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_YARDSTICK}", + "fill": 1, + "id": 10, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": true, + "min": true, + "show": true, + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "span": 6, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "SUCCESS Tx Total", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_tx_total" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + }, + { + "alias": "SUCCESS Rx Total", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_rx_total" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + }, + { + "alias": "SUCCESS ALLOWABLE LOST PACKETS", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "C", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_can_be_lost" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "SUCCESS CRITERIA: TX Total = Rx Total + Tolerated Loss", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Packets Per Second", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "35", + "id": 12, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 3, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.duration" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": "", + "title": "Test Interval", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30", + "id": 11, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 3, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "alias": "Test Duration", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.test_duration" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": "", + "title": "Test Duration", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30", + "id": 13, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 3, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "alias": "Test Precision", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.test_precision" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": "", + "title": "Test Precision", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30", + "id": 14, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 3, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "alias": "Tolerated Loss", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.tolerated_loss" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": "", + "title": "Tolerated Loss", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "New row", + "titleSize": "h6" + }, + { + "collapse": false, + "height": -153, + "panels": [ + { + "content": "<center>Packet size</center>", + "height": "30px", + "id": 15, + "links": [], + "mode": "html", + "span": 2, + "title": "", + "type": "text" + }, + { + "content": "<center>Theoretical Max Throughput (MPPS)</center>", + "height": "30px", + "id": 16, + "links": [], + "mode": "html", + "span": 2, + "title": "", + "type": "text" + }, + { + "content": "<center>Tx Throughput (MPPS)</center>", + "height": "30px", + "id": 17, + "links": [], + "mode": "html", + "span": 2, + "title": "", + "type": "text" + }, + { + "content": "<center>Rx Throughput (MPPS)</center>", + "height": "30px", + "id": 58, + "links": [], + "mode": "html", + "span": 2, + "title": "", + "type": "text" + }, + { + "content": "<center>Tot Sent </center>", + "height": "40px", + "id": 61, + "links": [], + "mode": "html", + "span": 1, + "title": "", + "type": "text" + }, + { + "content": "<center>Tot Received</center>", + "height": "30px", + "id": 62, + "links": [], + "mode": "html", + "span": 1, + "title": "", + "type": "text" + }, + { + "content": "<center>Tot Dropped</center>", + "height": "30px", + "id": 63, + "links": [], + "mode": "html", + "span": 1, + "title": "", + "type": "text" + }, + { + "content": "<center>Tot Can be Lost</center>", + "height": "30px", + "id": 64, + "links": [], + "mode": "html", + "span": 1, + "title": "", + "type": "text" + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6" + }, + { + "collapse": false, + "height": -224, + "panels": [ + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "hideTimeOverride": false, + "id": 18, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 2, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "alias": "Theoretical Max Throughput (Mpps)", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "hide": false, + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT mean(\"tg__0.Success_PktSize\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 68 AND $timeFilter GROUP BY time($__interval) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.PktSize" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "hideTimeOverride": false, + "id": 19, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 2, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "alias": "Max Throughput (Mpps)", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.theor_max_throughput\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 68 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.theor_max_throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 20, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 2, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_TxThroughput\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 68 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 69, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 2, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "last", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_RxThroughput\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 68 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "table", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 70, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 1, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_tx_total\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 68 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 71, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 1, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_rx_total\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 68 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 72, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 1, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_drop_total\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 68 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 73, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 1, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_can_be_lost\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 68 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 74, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 2, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "alias": "Theoretical Max Throughput (Mpps)", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "hide": false, + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT mean(\"tg__0.Success_PktSize\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 128 AND $timeFilter GROUP BY time($__interval) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.PktSize" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 75, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 2, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "alias": "Max Throughput (Mpps)", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Result_theor_max_throughput\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Result_pktSize\" = 128 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.theor_max_throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 76, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 2, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_TxThroughput\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 128 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 77, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 2, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_RxThroughput\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 128 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 78, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 1, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_tx_total\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 128 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 79, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 1, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_rx_total\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 128 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 80, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 1, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_drop_total\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 128 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 81, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 1, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_can_be_lost\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 128 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 82, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 2, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "alias": "Theoretical Max Throughput (Mpps)", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "hide": false, + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT mean(\"tg__0.Success_PktSize\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 256 AND $timeFilter GROUP BY time($__interval) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.PktSize" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 83, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 2, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "alias": "Max Throughput (Mpps)", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Result_theor_max_throughput\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Result_pktSize\" = 256 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.theor_max_throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 84, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 2, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_TxThroughput\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 256 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 85, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 2, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_RxThroughput\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 256 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 86, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 1, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_tx_total\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 256 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 87, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 1, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_rx_total\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 256 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 88, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 1, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_drop_total\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 256 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 89, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 1, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_can_be_lost\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 256 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 90, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 2, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "alias": "Theoretical Max Throughput (Mpps)", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "hide": false, + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT mean(\"tg__0.Success_PktSize\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 512 AND $timeFilter GROUP BY time($__interval) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.PktSize" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 91, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 2, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "alias": "Max Throughput (Mpps)", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Result_theor_max_throughput\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Result_pktSize\" = 512 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.theor_max_throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 92, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 2, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_TxThroughput\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 512 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 93, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 2, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_RxThroughput\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 512 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 94, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 1, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_tx_total\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 512 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 95, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 1, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_rx_total\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 512 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 96, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 1, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_drop_total\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 512 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 97, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 1, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_can_be_lost\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 512 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 98, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 2, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "alias": "Theoretical Max Throughput (Mpps)", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "hide": false, + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT mean(\"tg__0.Success_PktSize\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 1024 AND $timeFilter GROUP BY time($__interval) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.PktSize" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 99, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 2, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "alias": "Max Throughput (Mpps)", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Result_theor_max_throughput\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Result_pktSize\" = 1024 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.theor_max_throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 100, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 2, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_TxThroughput\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 1024 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 101, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 2, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_RxThroughput\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 1024 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 102, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 1, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_tx_total\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 1024 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 103, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 1, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_rx_total\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 1024 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 104, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 1, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_drop_total\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 1024 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 105, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 1, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_can_be_lost\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 1024 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 106, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 2, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "alias": "Theoretical Max Throughput (Mpps)", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "hide": false, + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT mean(\"tg__0.Success_PktSize\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 1280 AND $timeFilter GROUP BY time($__interval) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.PktSize" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 107, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 2, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "alias": "Max Throughput (Mpps)", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Result_theor_max_throughput\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Result_pktSize\" = 1280 AND $timeFilter AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.theor_max_throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 108, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 2, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_TxThroughput\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 1280 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 109, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 2, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_RxThroughput\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 1280 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 110, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 1, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_tx_total\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 1280 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 111, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 1, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_rx_total\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 1280 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 112, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 1, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_drop_total\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 1280 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 113, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 1, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_can_be_lost\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 1280 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 114, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 2, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "alias": "Theoretical Max Throughput (Mpps)", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "hide": false, + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT mean(\"tg__0.Success_PktSize\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 1518 AND $timeFilter GROUP BY time($__interval) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.PktSize" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 115, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 2, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "alias": "Max Throughput (Mpps)", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Result_theor_max_throughput\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Result_pktSize\" = 1518 AND $timeFilter AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.theor_max_throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "sum" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + }, + { + "op": "=", + "text": "", + "value": "" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 116, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 2, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_TxThroughput\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 1518 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 4, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 117, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 2, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_RxThroughput\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 1518 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 118, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 1, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_tx_total\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 1518 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 119, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 1, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_rx_total\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 1518 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 120, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 1, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_drop_total\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 1518 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "${DS_YARDSTICK}", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "height": "30px", + "id": 121, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 1, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"tg__0.Success_can_be_lost\") FROM \"tc_prox_baremetal_vpe-4\" WHERE \"tg__0.Success_PktSize\" = 1518 AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.Success_Throughput" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "tg__0.PktSize", + "operator": "=", + "value": "64" + } + ] + } + ], + "thresholds": "", + "title": "", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h3" + }, + { + "collapse": false, + "height": "40px", + "panels": [ + { + "content": "<h5 style=\"font-family:Verdana\"> <a style=\"color:#31A7D3\"><a style=\"font: 22px '#31A7D3'\"><center>Latency</center> </a></h5>", + "height": "40", + "id": 41, + "links": [], + "mode": "html", + "span": 12, + "title": "", + "type": "text" + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6" + }, + { + "collapse": false, + "height": 250, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_YARDSTICK}", + "fill": 1, + "height": "300px", + "id": 47, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": true, + "min": true, + "show": true, + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "span": 6, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "xe0 Latency Avg", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.LatencyAvg.9" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + }, + { + "alias": "xe0 Latency Max", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.LatencyMax.9" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "xe0 Latency", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "usec", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_YARDSTICK}", + "fill": 1, + "height": "300px", + "id": 48, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": true, + "min": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "span": 6, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "xe1 Latency Avg", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.LatencyAvg.10" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + }, + { + "alias": "xe1 Latency Max", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.LatencyMax.10" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "xe1 Latency", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "usec", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_YARDSTICK}", + "fill": 1, + "height": "300px", + "id": 49, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": true, + "min": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "span": 6, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "xe2 Latency Avg", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.LatencyAvg.11" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + }, + { + "alias": "xe2 Latency Max", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.LatencyMax.11" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "xe2 Latency", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "usec", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_YARDSTICK}", + "fill": 1, + "height": "300px", + "id": 50, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": true, + "min": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "span": 6, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "xe3 Latency Avg", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.LatencyAvg.12" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + }, + { + "alias": "xe3 Latency Max", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "tg__0.LatencyMax.12" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "xe3 Latency", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "usec", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "40px", + "panels": [ + { + "content": "<h5 style=\"font-family:Verdana\"> <a style=\"color:#31A7D3\"><a style=\"font: 22px '#31A7D3'\"><center>SUT CPU Utilization</center> </a></h5>", + "height": "40px", + "id": 51, + "links": [], + "mode": "html", + "span": 12, + "title": "", + "type": "text" + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6" + }, + { + "collapse": false, + "height": 250, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_YARDSTICK}", + "decimals": 5, + "fill": 1, + "height": "900px", + "id": 53, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": true, + "min": true, + "show": true, + "sort": "avg", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "span": 6, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "CPU 0 - Master", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "vnf__0.collect_stats.core.cpu.0.percent-user" + ], + "type": "field" + }, + { + "params": [], + "type": "distinct" + } + ] + ], + "tags": [] + }, + { + "alias": "CPU 1 - RX:inet0 - lbnetwork", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "vnf__0.collect_stats.core.cpu.1.percent-user" + ], + "type": "field" + }, + { + "params": [], + "type": "distinct" + } + ] + ], + "tags": [] + }, + { + "alias": "CPU 2 - RX:inet1 - lbnetwork", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "C", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "vnf__0.collect_stats.core.cpu.2.percent-user" + ], + "type": "field" + }, + { + "params": [], + "type": "distinct" + } + ] + ], + "tags": [] + }, + { + "alias": "CPU 3 - RX:cpe0 - lbnetwork", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT distinct(\"vnf__0.collect_stats.core.cpu.3.percent-user\") FROM \"tc_prox_baremetal_vpe-4\" WHERE $timeFilter GROUP BY time($__interval) fill(none)", + "rawQuery": false, + "refId": "D", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "vnf__0.collect_stats.core.cpu.3.percent-user" + ], + "type": "field" + }, + { + "params": [], + "type": "distinct" + } + ] + ], + "tags": [] + }, + { + "alias": "CPU 4 - RX:cpe1 - lbnetwork", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT distinct(\"vnf__0.collect_stats.core.cpu.4.percent-user\") FROM \"tc_prox_baremetal_vpe-4\" WHERE $timeFilter GROUP BY time($__interval) fill(none)", + "rawQuery": false, + "refId": "E", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "vnf__0.collect_stats.core.cpu.4.percent-user" + ], + "type": "field" + }, + { + "params": [], + "type": "distinct" + } + ] + ], + "tags": [] + }, + { + "alias": "CPU 5 - TX:cpe0 - QoS", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "F", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "vnf__0.collect_stats.core.cpu.5.percent-user" + ], + "type": "field" + }, + { + "params": [], + "type": "distinct" + } + ] + ], + "tags": [] + }, + { + "alias": "CPU 6 - TX:inet0", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "G", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "vnf__0.collect_stats.core.cpu.6.percent-user" + ], + "type": "field" + }, + { + "params": [], + "type": "distinct" + } + ] + ], + "tags": [] + }, + { + "alias": "CPU 7 - TX:cpe1 - QoS", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "H", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "vnf__0.collect_stats.core.cpu.7.percent-user" + ], + "type": "field" + }, + { + "params": [], + "type": "distinct" + } + ] + ], + "tags": [] + }, + { + "alias": "CPU 8 - TX:inet1", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "I", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "vnf__0.collect_stats.core.cpu.8.percent-user" + ], + "type": "field" + }, + { + "params": [], + "type": "distinct" + } + ] + ], + "tags": [] + }, + { + "alias": "CPU 9 - Worker Downstream - qinqencapv4", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "J", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "vnf__0.collect_stats.core.cpu.9.percent-user" + ], + "type": "field" + }, + { + "params": [], + "type": "distinct" + } + ] + ], + "tags": [] + }, + { + "alias": "CPU 10 - Worker Downstream - qinqencapv4", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "K", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "vnf__0.collect_stats.core.cpu.10.percent-user" + ], + "type": "field" + }, + { + "params": [], + "type": "distinct" + } + ] + ], + "tags": [] + }, + { + "alias": "CPU 11 - Worker Downstream - qinqencapv4", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "L", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "vnf__0.collect_stats.core.cpu.11.percent-user" + ], + "type": "field" + }, + { + "params": [], + "type": "distinct" + } + ] + ], + "tags": [] + }, + { + "alias": "CPU 12 - Worker Downstream - qinqencapv4", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "M", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "vnf__0.collect_stats.core.cpu.12.percent-user" + ], + "type": "field" + }, + { + "params": [], + "type": "distinct" + } + ] + ], + "tags": [] + }, + { + "alias": "CPU 13 - Worker Upstream - acl, police, untag and routing", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "N", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "vnf__0.collect_stats.core.cpu.13.percent-user" + ], + "type": "field" + }, + { + "params": [], + "type": "distinct" + } + ] + ], + "tags": [] + }, + { + "alias": "CPU 14 - Worker Upstream - acl, police, untag and routing", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "O", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "vnf__0.collect_stats.core.cpu.14.percent-user" + ], + "type": "field" + }, + { + "params": [], + "type": "distinct" + } + ] + ], + "tags": [] + }, + { + "alias": "CPU 15 - Worker Upstream - acl, police, untag and routing", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "P", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "vnf__0.collect_stats.core.cpu.15.percent-user" + ], + "type": "field" + }, + { + "params": [], + "type": "distinct" + } + ] + ], + "tags": [] + }, + { + "alias": "CPU 16 - Worker Upstream - acl, police, untag and routing", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "none" + ], + "type": "fill" + } + ], + "measurement": "tc_prox_baremetal_vpe-4", + "orderByTime": "ASC", + "policy": "default", + "refId": "Q", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "vnf__0.collect_stats.core.cpu.17.percent-user" + ], + "type": "field" + }, + { + "params": [], + "type": "distinct" + } + ] + ], + "tags": [] + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "SUT CPU Utilization", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "% Utilization", + "logBase": 1, + "max": "100", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6" + } + ], + "schemaVersion": 14, + "style": "dark", + "tags": [ + "yardstick", + "NSB", + "Prox", + "vpe", + "4Port", + "BM" + ], + "templating": { + "list": [] + }, + "time": { + "from": "2018-06-18T16:42:35.488Z", + "to": "2018-06-18T17:57:41.922Z" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "Prox_BM_vpe-4Port", + "version": 7 +}
\ No newline at end of file diff --git a/dashboard/opnfv_yardstick_tc058.json b/dashboard/opnfv_yardstick_tc058.json index 55b5a5f33..ed2a1750c 100644 --- a/dashboard/opnfv_yardstick_tc058.json +++ b/dashboard/opnfv_yardstick_tc058.json @@ -6,7 +6,7 @@ "gnetId": null, "graphTooltip": 0, "hideControls": false, - "id": 33, + "id": null, "links": [], "refresh": "1m", "rows": [ diff --git a/docker/Dockerfile b/docker/Dockerfile index 62ea0d037..71ce6b584 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -24,9 +24,9 @@ ENV YARDSTICK_REPO_DIR="${REPOS_DIR}/yardstick/" \ RELENG_REPO_DIR="${REPOS_DIR}/releng" \ STORPERF_REPO_DIR="${REPOS_DIR}/storperf" -RUN apt-get update && apt-get install -y git python python-setuptools python-pip && apt-get -y autoremove && apt-get clean +RUN apt-get update && apt-get install -y git python python-setuptools python-pip iputils-ping && apt-get -y autoremove && apt-get clean RUN easy_install -U setuptools==30.0.0 -RUN pip install appdirs==1.4.0 pyopenssl==17.5.0 python-openstackclient==3.11.0 python-heatclient==1.11.0 ansible==2.4.2 +RUN pip install appdirs==1.4.0 pyopenssl==17.5.0 python-openstackclient==3.12.0 python-heatclient==1.11.0 ansible==2.5.5 RUN mkdir -p ${REPOS_DIR} @@ -40,7 +40,7 @@ RUN git clone --depth 1 -b $BRANCH https://gerrit.opnfv.org/gerrit/yardstick ${Y RUN git clone --depth 1 https://gerrit.opnfv.org/gerrit/releng ${RELENG_REPO_DIR} RUN git clone --depth 1 -b $BRANCH https://gerrit.opnfv.org/gerrit/storperf ${STORPERF_REPO_DIR} -RUN ansible-playbook -c local -vvv -e INSTALLATION_MODE="container" ${YARDSTICK_REPO_DIR}/ansible/install.yaml +RUN ansible-playbook -i ${YARDSTICK_REPO_DIR}/ansible/install-inventory.ini -c local -vvv -e INSTALLATION_MODE="container" ${YARDSTICK_REPO_DIR}/ansible/install.yaml RUN ${YARDSTICK_REPO_DIR}/docker/supervisor.sh @@ -51,6 +51,8 @@ EXPOSE 5000 5672 ADD http://download.cirros-cloud.net/0.3.5/cirros-0.3.5-x86_64-disk.img ${IMAGE_DIR} ADD http://cloud-images.ubuntu.com/xenial/current/xenial-server-cloudimg-amd64-disk1.img ${IMAGE_DIR} +# For developers: when `docker build ...` is running from YARDSTICK_REPO_DIR, please change +# path `./exec_tests.sh` -> `./docker/exec_tests.sh``. COPY ./exec_tests.sh /usr/local/bin/ ENV NSB_DIR="/opt/nsb_bin" diff --git a/docker/Dockerfile.aarch64.patch b/docker/Dockerfile.aarch64.patch index 6c7381284..2e2808ed1 100644 --- a/docker/Dockerfile.aarch64.patch +++ b/docker/Dockerfile.aarch64.patch @@ -1,14 +1,14 @@ -From: ting wu <ting.wu@enea.com> -Date: Tue, 8 May 2018 14:02:52 +0200 -Subject: [PATCH][PATCH] Patch for Yardstick AARCH64 Docker file +From: Cristina Pauna <cristina.pauna@enea.com> +Date: Mon, 23 Jul 2018 15:16:59 +0300 +Subject: [PATCH] Patch for Yardstick AARCH64 Docker file -Signed-off-by: ting wu <ting.wu@enea.com> +Signed-off-by: Cristina Pauna <cristina.pauna@enea.com> --- - docker/Dockerfile | 11 ++++++----- - 1 file changed, 6 insertions(+), 5 deletions(-) + docker/Dockerfile | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile -index 62ea0d0..f2f41771 100644 +index 71ce6b58..fce7c116 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -7,9 +7,9 @@ @@ -27,13 +27,23 @@ index 62ea0d0..f2f41771 100644 RELENG_REPO_DIR="${REPOS_DIR}/releng" \ STORPERF_REPO_DIR="${REPOS_DIR}/storperf" --RUN apt-get update && apt-get install -y git python python-setuptools python-pip && apt-get -y autoremove && apt-get clean -+RUN apt-get update && apt-get install -y git python python-setuptools python-pip && apt-get -y autoremove && \ +-RUN apt-get update && apt-get install -y git python python-setuptools python-pip iputils-ping && apt-get -y autoremove && apt-get clean ++RUN apt-get update && apt-get install -y git python python-setuptools python-pip iputils-ping && apt-get -y autoremove && \ + apt-get install -y libssl-dev && apt-get -y install libffi-dev && apt-get clean RUN easy_install -U setuptools==30.0.0 - RUN pip install appdirs==1.4.0 pyopenssl==17.5.0 python-openstackclient==3.11.0 python-heatclient==1.11.0 ansible==2.4.2 + RUN pip install appdirs==1.4.0 pyopenssl==17.5.0 python-openstackclient==3.12.0 python-heatclient==1.11.0 ansible==2.5.5 -@@ -48,8 +49,8 @@ RUN echo "daemon off;" >> /etc/nginx/nginx.conf +@@ -40,7 +41,8 @@ RUN git clone --depth 1 -b $BRANCH https://gerrit.opnfv.org/gerrit/yardstick ${Y + RUN git clone --depth 1 https://gerrit.opnfv.org/gerrit/releng ${RELENG_REPO_DIR} + RUN git clone --depth 1 -b $BRANCH https://gerrit.opnfv.org/gerrit/storperf ${STORPERF_REPO_DIR} + +-RUN ansible-playbook -i ${YARDSTICK_REPO_DIR}/ansible/install-inventory.ini -c local -vvv -e INSTALLATION_MODE="container" ${YARDSTICK_REPO_DIR}/ansible/install.yaml ++RUN sed -i -e '/- configure_gui/d' ${YARDSTICK_REPO_DIR}/ansible/install.yaml && \ ++ ansible-playbook -i ${YARDSTICK_REPO_DIR}/ansible/install-inventory.ini -c local -vvv -e INSTALLATION_MODE="container" ${YARDSTICK_REPO_DIR}/ansible/install.yaml + + RUN ${YARDSTICK_REPO_DIR}/docker/supervisor.sh + +@@ -48,8 +50,8 @@ RUN echo "daemon off;" >> /etc/nginx/nginx.conf # nginx=5000, rabbitmq=5672 EXPOSE 5000 5672 @@ -42,6 +52,5 @@ index 62ea0d0..f2f41771 100644 +ADD http://download.cirros-cloud.net/daily/20161201/cirros-d161201-aarch64-disk.img ${IMAGE_DIR} +ADD http://cloud-images.ubuntu.com/xenial/current/xenial-server-cloudimg-arm64-disk1.img ${IMAGE_DIR} - COPY ./exec_tests.sh /usr/local/bin/ - - + # For developers: when `docker build ...` is running from YARDSTICK_REPO_DIR, please change + # path `./exec_tests.sh` -> `./docker/exec_tests.sh``. diff --git a/docker/k8s/Dockerfile b/docker/k8s/Dockerfile new file mode 100644 index 000000000..2f8d9b161 --- /dev/null +++ b/docker/k8s/Dockerfile @@ -0,0 +1,39 @@ +############################################################################## +# 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 +############################################################################## + +FROM ubuntu:16.04 + +LABEL image=opnfv/yardstick-image-k8s + +ARG BRANCH=master + +# GIT repo directory +ENV CLONE_DEST="/opt/tempT" + +RUN apt-get update && apt-get install -y \ + git bc bonnie++ fio gcc iperf3 ethtool \ + iproute2 linux-tools-common linux-tools-generic \ + lmbench make netperf patch perl rt-tests stress \ + sysstat iputils-ping openssh-server sudo && \ + apt-get -y autoremove && apt-get clean + +RUN rm -rf -- ${CLONE_DEST} +RUN git clone https://github.com/kdlucas/byte-unixbench.git ${CLONE_DEST} +RUN mkdir -p ${CLONE_DEST}/UnixBench/ + +RUN git clone https://github.com/beefyamoeba5/ramspeed.git ${CLONE_DEST}/RAMspeed +WORKDIR ${CLONE_DEST}/RAMspeed/ramspeed-2.6.0 +RUN mkdir -p ${CLONE_DEST}/RAMspeed/ramspeed-2.6.0/temp +RUN bash build.sh + +RUN git clone https://github.com/beefyamoeba5/cachestat.git ${CLONE_DEST}/Cachestat + +WORKDIR / + +CMD /bin/bash diff --git a/docs/release/release-notes/release-notes.rst b/docs/release/release-notes/release-notes.rst index 6598a2751..daa4b8187 100644 --- a/docs/release/release-notes/release-notes.rst +++ b/docs/release/release-notes/release-notes.rst @@ -36,6 +36,15 @@ Version History | *Date* | *Version* | *Comment* | | | | | +-------------------+-----------+---------------------------------+ +| Jul 2, 2018 | 6.2.1 | Yardstick for Fraser release | +| | | | ++-------------------+-----------+---------------------------------+ +| Jun 29, 2018 | 6.2.0 | Yardstick for Fraser release | +| | | | ++-------------------+-----------+---------------------------------+ +| May 25, 2018 | 6.1.0 | Yardstick for Fraser release | +| | | | ++-------------------+-----------+---------------------------------+ | April 27, 2018 | 6.0.0 | Yardstick for Fraser release | | | | | +-------------------+-----------+---------------------------------+ @@ -117,19 +126,19 @@ Release Data | **Project** | Yardstick | | | | +--------------------------------+-----------------------+ -| **Repo/tag** | yardstick/opnfv-6.0.0 | +| **Repo/tag** | yardstick/opnfv-6.2.0 | | | | +--------------------------------+-----------------------+ -| **Yardstick Docker image tag** | opnfv-6.0.0 | +| **Yardstick Docker image tag** | opnfv-6.2.0 | | | | +--------------------------------+-----------------------+ | **Release designation** | Fraser | | | | +--------------------------------+-----------------------+ -| **Release date** | April 27, 2018 | +| **Release date** | Jun 29, 2018 | | | | +--------------------------------+-----------------------+ -| **Purpose of the delivery** | OPNFV Fraser 6.0.0 | +| **Purpose of the delivery** | OPNFV Fraser 6.2.0 | | | | +--------------------------------+-----------------------+ @@ -148,7 +157,7 @@ Documents Software Deliverables --------------------- - - The Yardstick Docker image: https://hub.docker.com/r/opnfv/yardstick (tag: opnfv-6.0.0) + - The Yardstick Docker image: https://hub.docker.com/r/opnfv/yardstick (tag: opnfv-6.2.0) List of Contexts ^^^^^^^^^^^^^^^^ @@ -174,7 +183,7 @@ List of Contexts List of Runners ^^^^^^^^^^^^^^^ -Note: Yardstick Fraser 6.0.0 add two new Runners, "Dynamictp" and "Search". +.. note:: Yardstick Fraser 6.0.0 add two new Runners, "Dynamictp" and "Search". +---------------+-------------------------------------------------------+ | **Runner** | **Description** | @@ -271,6 +280,8 @@ List of Scenarios New Test cases -------------- +.. note:: Yardstick Fraser 6.1.0 added two new test cases, "TC092" and "TC093". + * Generic NFVI test cases * OPNFV_YARDSTICK_TCO84 - SPEC CPU 2006 for VM @@ -280,6 +291,8 @@ New Test cases * OPNFV_YARDSTICK_TC087 - SDN Controller resilience in non-HA configuration * OPNFV_YARDSTICK_TC090 - Control node Openstack service down - database instance * OPNFV_YARDSTICK_TC091 - Control node Openstack service down - heat-api + * OPNFV_YARDSTICK_TC092 - SDN Controller resilience in HA configuration + * OPNFV_YARDSTICK_TC093 - SDN Vswitch resilience in non-HA or HA configuration Version Change @@ -384,6 +397,132 @@ Known Issues/Faults Corrected Faults ---------------- +Fraser 6.2.1: + ++--------------------+--------------------------------------------------------------------------+ +| **JIRA REFERENCE** | **DESCRIPTION** | ++====================+==========================================================================+ +| YARDSTICK-1147 | Fix ansible scripts for running in container | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1157 | Bug Fix: correct the file path to build docker file | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1276 | Bugfix: docker build failed | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1280 | Bugfix: uwsgi config file yardstick.ini output error | ++--------------------+--------------------------------------------------------------------------+ + +Fraser 6.2.0: + ++--------------------+--------------------------------------------------------------------------+ +| **JIRA REFERENCE** | **DESCRIPTION** | ++====================+==========================================================================+ +| YARDSTICK-1246 | Update pmd/lcore mask for OVS-DPDK context | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-837 | Move tests: unit/network_services/{lib/,collector/,*.py} | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1144 | Correctly set PYTHONPATH in Dockerfile | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1205 | Set "cmd2" library to version 0.8.6 | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1204 | Bump oslo.messaging version to 5.36.0 | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1210 | Remove __init__ method overriding in HeatContextTestCase | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1189 | Error when adding SR-IOV interfaces in SR-IOV context | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1214 | Remove AnsibleCommon class method mock | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1159 | Add --hwlb options as a command line argument for SampleVNF | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1203 | Add scale out TCs with availability zone support | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1167 | Do not start collectd twice when SampleVNF is running on Baremetal | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1188 | Add "host_name_separator" variable to Context class | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1112 | MQ startup process refactor | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1229 | Cleanup BaseMonitor unit tests | ++--------------------+--------------------------------------------------------------------------+ +| - | Configure ACL via static file | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1191 | Use TRex release v2.41 to support both x86 and aarch64 | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1106 | Add IxNetwork API Python Binding package | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1224 | Cleanup TestYardstickNSCli class | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1225 | Remove print out of logger exception in TestUtils | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1194 | Add "duration" parameter to test case definition | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1209 | Remove instantiated contexts in "test_task" | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1192 | Standalone XML machine type is not longer valid | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1197 | Refactor RFC2455 TRex traffic profile injection | ++--------------------+--------------------------------------------------------------------------+ +| - | Fix "os.path" mock problems during tests | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1218 | Refactor "utils.parse_ini_file" testing | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1179 | Start nginx and uwsgi servicies only in not container mode | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1177 | Install dependencies: bare-metal, standalone | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1126 | Migrate install.sh script to ansible | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1146 | Fix nsb_setup.sh script | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1247 | NSB setup inventory name changed | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1116 | Changed IxNextgen library load in IXIA RFC2544 traffic generator call. | ++--------------------+--------------------------------------------------------------------------+ +| - | Corrected scale-up command line arguments | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-878 | OpenStack client replacement | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1222 | Bugfix: HA kill process recovery has a conflict | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1139 | Add "os_cloud_config" as a new context flag parameter | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1255 | Extended Context class with get_physical_nodes functionality | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1244 | NSB NFVi BNG test fails to run - stops after one step | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1219 | Decrease Sampling interval | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1101 | NSB NFVi PROX BNG losing many packets | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1217 | Fix NSB NfVi support for 25 and 40Gbps | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1185 | NSB Topology fix for Prox 4 port test case | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-966 | Convert SLA asserts to raises | ++--------------------+--------------------------------------------------------------------------+ + +Fraser 6.1.0: + ++--------------------+--------------------------------------------------------------------------+ +| **JIRA REFERENCE** | **DESCRIPTION** | ++====================+==========================================================================+ +| YARDSTICK-995 | Test case spec for SDN Virtual Switch resilience | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1097 | Add pod.yaml file for APEX installer | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1122 | Remove unused code in SampleVNF | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1125 | Update samples/test_suite.yaml | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1132 | Document for Euphrates test case results | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1138 | Support Restart Operation | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1142 | start_service script fails to start openvswitch service in centos distro | ++--------------------+--------------------------------------------------------------------------+ +| YARDSTICK-1165 | Bugfix: openrc api dump should be safe_dump | ++--------------------+--------------------------------------------------------------------------+ + Fraser 6.0.0: +--------------------+--------------------------------------------------------------------------+ diff --git a/docs/release/results/euphrates_fraser_comparison.rst b/docs/release/results/euphrates_fraser_comparison.rst new file mode 100644 index 000000000..53dfb994f --- /dev/null +++ b/docs/release/results/euphrates_fraser_comparison.rst @@ -0,0 +1,602 @@ +.. This work is licensed under a Creative Commons Attribution 4.0 International +.. License. +.. http://creativecommons.org/licenses/by/4.0 + +======================================================= +Test results analysis for Euphrates and Fraser releases +======================================================= + +TC002 +----- + +The round-trip-time (RTT) between 2 VMs on different blades is measured using +ping. + +Most test run measurements result on average between 0.39 and 4.00 ms. +Compared with Euphrates release, the average RTT result of the same pod experiences +a slight decline in Fraser release. For example, the average RTT of arm-pod5 is +1.518 in Ehphrates and 1.714 in Fraser. The average RTT of intel-pod18 is 1.6575 +ms in Ehphrates and 1.856 ms in Fraser. + +{ + + "huawei-pod2:stable/euphrates": [0.3925], + + "lf-pod2:stable/euphrates": [0.5315], + + "lf-pod1:stable/euphrates": [0.62], + + "huawei-pod2:stable/fraser": [0.677], + + "lf-pod1:stable/fraser": [0.725], + + "flex-pod2:stable/euphrates": [0.795], + + "huawei-pod12:stable/euphrates": [0.87], + + "ericsson-pod1:stable/fraser": [0.9165], + + "huawei-pod12:stable/fraser": [1.0465], + + "lf-pod2:stable/fraser": [1.2325], + + "intel-pod5:stable/euphrates": [1.25], + + "ericsson-virtual3:stable/euphrates": [1.2655], + + "ericsson-pod1:stable/euphrates": [1.372], + + "zte-pod2:stable/fraser": [1.395], + + "arm-pod5:stable/euphrates": [1.518], + + "huawei-virtual4:stable/euphrates": [1.5355], + + "ericsson-virtual4:stable/fraser": [1.582], + + "huawei-virtual3:stable/euphrates": [1.606], + + "intel-pod18:stable/euphrates": [1.6575], + + "huawei-virtual4:stable/fraser": [1.697], + + "huawei-virtual8:stable/euphrates": [1.709], + + "arm-pod5:stable/fraser": [1.714], + + "huawei-virtual3:stable/fraser": [1.716], + + "intel-pod18:stable/fraser": [1.856], + + "huawei-virtual2:stable/euphrates": [1.872], + + "arm-pod6:stable/euphrates": [1.895], + + "huawei-virtual2:stable/fraser": [1.964], + + "huawei-virtual1:stable/fraser": [1.9765], + + "huawei-virtual9:stable/euphrates": [2.0745], + + "arm-pod6:stable/fraser": [2.209], + + "huawei-virtual1:stable/euphrates": [2.495], + + "ericsson-virtual2:stable/euphrates": [2.7895], + + "ericsson-virtual4:stable/euphrates": [3.768], + + "ericsson-virtual1:stable/euphrates": [3.8035], + + "ericsson-virtual3:stable/fraser": [3.9175], + + "ericsson-virtual2:stable/fraser": [4.004] + +} + +TC010 +----- + +The tool we use to measure memory read latency is lmbench, which is a series of +micro benchmarks intended to measure basic operating system and hardware system +metrics. Compared with Euphrates release, the memory read latency of the same pod +also experience a slight decline. Virtual pods seem to have a higher memory read +latency than physical pods. Compared with X86 pods, the memory read latency of +arm pods is significant higher. + +{ + + "ericsson-pod1:stable/euphrates": [5.7785], + + "flex-pod2:stable/euphrates": [5.908], + + "ericsson-virtual1:stable/euphrates": [6.412], + + "intel-pod18:stable/euphrates": [6.5905], + + "intel-pod5:stable/euphrates": [6.6975], + + "ericsson-pod1:stable/fraser": [7.0645], + + "ericsson-virtual4:stable/euphrates": [7.183], + + "intel-pod18:stable/fraser": [7.4465], + + "zte-pod2:stable/fraser": [8.1865], + + "ericsson-virtual2:stable/euphrates": [8.4985], + + "huawei-pod2:stable/euphrates": [8.877], + + "huawei-pod12:stable/euphrates": [9.091], + + "huawei-pod2:stable/fraser": [9.236], + + "huawei-pod12:stable/fraser": [9.615], + + "ericsson-virtual3:stable/euphrates": [9.719], + + "ericsson-virtual2:stable/fraser": [9.8925], + + "huawei-virtual4:stable/euphrates": [10.1195], + + "huawei-virtual3:stable/euphrates": [10.19], + + "huawei-virtual2:stable/fraser": [10.22], + + "huawei-virtual1:stable/euphrates": [10.3045], + + "huawei-virtual9:stable/euphrates": [10.318], + + "ericsson-virtual4:stable/fraser": [10.5465], + + "ericsson-virtual3:stable/fraser": [10.9355], + + "huawei-virtual3:stable/fraser": [10.95], + + "huawei-virtual2:stable/euphrates": [11.274], + + "huawei-virtual4:stable/fraser": [11.557], + + "lf-pod1:stable/euphrates": [15.7025], + + "lf-pod2:stable/euphrates": [15.8495], + + "lf-pod2:stable/fraser": [16.5595], + + "lf-pod1:stable/fraser": [16.8395], + + "arm-pod5:stable/euphrates": [18.092], + + "arm-pod5:stable/fraser": [18.744], + + "huawei-virtual1:stable/fraser": [19.8235], + + "huawei-virtual8:stable/euphrates": [33.999], + + "arm-pod6:stable/euphrates": [41.5605], + + "arm-pod6:stable/fraser": [55.804] + +} + +TC011 +----- + +Iperf3 is a tool for evaluating the packet delay variation between 2 VMs on +different blades. In general, the packet delay variation of the two releases +look similar. + +{ + + "arm-pod6:stable/fraser": [1], + + "ericsson-pod1:stable/fraser": [1], + + "ericsson-virtual2:stable/fraser": [1], + + "ericsson-virtual3:stable/fraser": [1], + + "lf-pod2:stable/fraser": [1], + + "huawei-virtual1:stable/fraser": [2997], + + "huawei-virtual2:stable/euphrates": [2997], + + "flex-pod2:stable/euphrates": [2997.5], + + "huawei-virtual3:stable/euphrates": [2998], + + "huawei-virtual3:stable/fraser": [2999], + + "huawei-virtual9:stable/euphrates": [3000], + + "huawei-virtual8:stable/euphrates": [3001], + + "huawei-virtual4:stable/euphrates": [3002], + + "huawei-virtual4:stable/fraser": [3002], + + "ericsson-virtual3:stable/euphrates": [3006], + + "huawei-virtual1:stable/euphrates": [3007], + + "ericsson-virtual2:stable/euphrates": [3009], + + "intel-pod18:stable/euphrates": [3010], + + "ericsson-virtual4:stable/euphrates": [3017], + + "lf-pod2:stable/euphrates": [3021], + + "arm-pod5:stable/euphrates": [3022], + + "arm-pod6:stable/euphrates": [3022], + + "ericsson-pod1:stable/euphrates": [3022], + + "huawei-pod12:stable/euphrates": [3022], + + "huawei-pod12:stable/fraser": [3022], + + "huawei-pod2:stable/euphrates": [3022], + + "huawei-pod2:stable/fraser": [3022], + + "intel-pod18:stable/fraser": [3022], + + "intel-pod5:stable/euphrates": [3022], + + "lf-pod1:stable/euphrates": [3022], + + "lf-pod1:stable/fraser": [3022], + + "zte-pod2:stable/fraser": [3022], + + "huawei-virtual2:stable/fraser": [3025] + +} + +TC012 +----- + +Lmbench is also used to measure the memory read and write bandwidth. +Like TC010, compared with Euphrates release, the memory read and write bandwidth +of the same pod also experience a slight decline. And compared with X86 pods, the memory +read and write bandwidth of arm pods is significant lower. + +{ + + "lf-pod1:stable/euphrates": [22912.39], + + "lf-pod2:stable/euphrates": [22637.67], + + "lf-pod1:stable/fraser": [20552.9], + + "flex-pod2:stable/euphrates": [20229.99], + + "lf-pod2:stable/fraser": [20058.925], + + "ericsson-pod1:stable/fraser": [18930.78], + + "intel-pod18:stable/fraser": [18757.545], + + "ericsson-virtual1:stable/euphrates": [17474.965], + + "ericsson-pod1:stable/euphrates": [17127.38], + + "ericsson-virtual4:stable/euphrates": [16219.97], + + "ericsson-virtual2:stable/euphrates": [15652.28], + + "ericsson-virtual3:stable/euphrates": [15551.26], + + "ericsson-virtual4:stable/fraser": [15389.465], + + "ericsson-virtual2:stable/fraser": [15343.79], + + "huawei-pod2:stable/euphrates": [15017.2], + + "huawei-pod2:stable/fraser": [14870.78], + + "huawei-virtual4:stable/euphrates": [14266.34], + + "huawei-virtual1:stable/euphrates": [14233.035], + + "huawei-virtual3:stable/euphrates": [14227.63], + + "zte-pod2:stable/fraser": [14157.99], + + "huawei-pod12:stable/euphrates": [14147.245], + + "huawei-pod12:stable/fraser": [14126.99], + + "intel-pod18:stable/euphrates": [14058.33], + + "huawei-virtual3:stable/fraser": [13929.67], + + "huawei-virtual2:stable/euphrates": [13862.85], + + "huawei-virtual4:stable/fraser": [13847.155], + + "huawei-virtual2:stable/fraser": [13702.92], + + "huawei-virtual1:stable/fraser": [13496.45], + + "intel-pod5:stable/euphrates": [13280.32], + + "ericsson-virtual3:stable/fraser": [12733.19], + + "huawei-virtual9:stable/euphrates": [12559.445], + + "huawei-virtual8:stable/euphrates": [8998.02], + + "arm-pod5:stable/euphrates": [4388.875], + + "arm-pod5:stable/fraser": [4326.11], + + "arm-pod6:stable/euphrates": [4260.2], + + "arm-pod6:stable/fraser": [3809.885] + +} + +TC014 +----- + +The Unixbench is used to evaluate the IaaS processing speed with regards to +score of single CPU running and parallel running. Below are the single CPU running +scores. It can be seen that the processing test results vary from scores 715 to 3737. +In general, the single CPU score of the two releases look similar. + +{ + + "lf-pod2:stable/fraser": [3737.6], + + "lf-pod2:stable/euphrates": [3723.95], + + "lf-pod1:stable/fraser": [3702.7], + + "lf-pod1:stable/euphrates": [3669], + + "intel-pod5:stable/euphrates": [3388.6], + + "intel-pod18:stable/euphrates": [3298.4], + + "flex-pod2:stable/euphrates": [3208.6], + + "ericsson-pod1:stable/fraser": [3131.6], + + "intel-pod18:stable/fraser": [3098.1], + + "ericsson-virtual1:stable/euphrates": [2988.9], + + "zte-pod2:stable/fraser": [2831.4], + + "ericsson-pod1:stable/euphrates": [2669.1], + + "ericsson-virtual4:stable/euphrates": [2598.5], + + "ericsson-virtual2:stable/fraser": [2559.7], + + "ericsson-virtual3:stable/euphrates": [2553.15], + + "huawei-pod2:stable/euphrates": [2531.2], + + "huawei-pod2:stable/fraser": [2528.9], + + "ericsson-virtual4:stable/fraser": [2527.8], + + "ericsson-virtual2:stable/euphrates": [2526.9], + + "huawei-virtual4:stable/euphrates": [2407.4], + + "huawei-virtual3:stable/fraser": [2379.1], + + "huawei-virtual3:stable/euphrates": [2374.6], + + "huawei-virtual4:stable/fraser": [2362.1], + + "huawei-virtual2:stable/euphrates": [2326.4], + + "huawei-virtual9:stable/euphrates": [2324.95], + + "huawei-virtual1:stable/euphrates": [2302.6], + + "huawei-virtual2:stable/fraser": [2299.3], + + "huawei-pod12:stable/euphrates": [2232.2], + + "huawei-pod12:stable/fraser": [2229], + + "huawei-virtual1:stable/fraser": [2171.3], + + "ericsson-virtual3:stable/fraser": [2104.8], + + "huawei-virtual8:stable/euphrates": [2085.3], + + "arm-pod5:stable/fraser": [1764.2], + + "arm-pod5:stable/euphrates": [1754.4], + + "arm-pod6:stable/euphrates": [716.15], + + "arm-pod6:stable/fraser": [715.4] + +} + +TC069 +----- + +With the block size changing from 1 kb to 512 kb, the memory write bandwidth +tends to become larger first and then smaller within every run test. Below are +the scores for 32mb block array. + +{ + + "intel-pod18:stable/euphrates": [18871.79], + + "intel-pod18:stable/fraser": [16939.24], + + "intel-pod5:stable/euphrates": [16055.79], + + "arm-pod6:stable/euphrates": [13327.02], + + "arm-pod6:stable/fraser": [11895.71], + + "flex-pod2:stable/euphrates": [9384.585], + + "zte-pod2:stable/fraser": [9375.33], + + "ericsson-pod1:stable/euphrates": [9331.535], + + "huawei-pod12:stable/euphrates": [9164.88], + + "ericsson-pod1:stable/fraser": [9140.42], + + "huawei-pod2:stable/euphrates": [9026.52], + + "huawei-pod12:stable/fraser": [8993.37], + + "huawei-virtual9:stable/euphrates": [8825.805], + + "huawei-pod2:stable/fraser": [8794.01], + + "huawei-virtual2:stable/fraser": [7670.21], + + "ericsson-virtual1:stable/euphrates": [7615.97], + + "ericsson-virtual4:stable/euphrates": [7539.23], + + "arm-pod5:stable/fraser": [7479.32], + + "arm-pod5:stable/euphrates": [7403.38], + + "huawei-virtual3:stable/euphrates": [7247.89], + + "ericsson-virtual2:stable/fraser": [7219.21], + + "huawei-virtual2:stable/euphrates": [7205.35], + + "huawei-virtual1:stable/euphrates": [7196.405], + + "ericsson-virtual3:stable/euphrates": [7173.72], + + "huawei-virtual4:stable/euphrates": [7131.47], + + "ericsson-virtual2:stable/euphrates": [7129.08], + + "huawei-virtual4:stable/fraser": [7059.045], + + "huawei-virtual3:stable/fraser": [7023.57], + + "lf-pod1:stable/euphrates": [6928.18], + + "lf-pod2:stable/euphrates": [6875.88], + + "lf-pod2:stable/fraser": [6834.7], + + "lf-pod1:stable/fraser": [6775.27], + + "ericsson-virtual4:stable/fraser": [6522.86], + + "ericsson-virtual3:stable/fraser": [5835.59], + + "huawei-virtual8:stable/euphrates": [5729.705], + + "huawei-virtual1:stable/fraser": [5617.12] + +} + +TC082 +----- + +For this test case, we use perf to measure context-switches under load. +High context switch rates are not themselves an issue, but they may point the +way to a more significant problem. + +{ + + "zte-pod2:stable/fraser": [306.5], + + "huawei-pod12:stable/euphrates": [316], + + "lf-pod2:stable/fraser": [337.5], + + "intel-pod18:stable/euphrates": [340], + + "intel-pod18:stable/fraser": [343.5], + + "intel-pod5:stable/euphrates": [357.5], + + "ericsson-pod1:stable/euphrates": [384], + + "lf-pod2:stable/euphrates": [394.5], + + "huawei-pod12:stable/fraser": [399], + + "lf-pod1:stable/euphrates": [435], + + "lf-pod1:stable/fraser": [454], + + "flex-pod2:stable/euphrates": [476], + + "huawei-pod2:stable/euphrates": [518], + + "huawei-pod2:stable/fraser": [544.5], + + "arm-pod5:stable/euphrates": [869.5], + + "huawei-virtual9:stable/euphrates": [1002], + + "huawei-virtual4:stable/fraser": [1138], + + "huawei-virtual4:stable/euphrates": [1174], + + "huawei-virtual3:stable/euphrates": [1239], + + "ericsson-pod1:stable/fraser": [1305], + + "huawei-virtual2:stable/euphrates": [1430], + + "huawei-virtual3:stable/fraser": [1433], + + "huawei-virtual1:stable/fraser": [1470], + + "huawei-virtual1:stable/euphrates": [1489], + + "arm-pod6:stable/fraser": [1738.5], + + "arm-pod6:stable/euphrates": [1883.5] + +} + +TC083 +----- + +TC083 measures network latency and throughput between VMs using netperf. +The test results shown below are for UDP throughout. + +{ + + "lf-pod1:stable/euphrates": [2204.42], + + "lf-pod2:stable/fraser": [1893.39], + + "intel-pod18:stable/euphrates": [1835.55], + + "lf-pod2:stable/euphrates": [1676.705], + + "intel-pod5:stable/euphrates": [1612.555], + + "zte-pod2:stable/fraser": [1543.995], + + "lf-pod1:stable/fraser": [1480.86], + + "intel-pod18:stable/fraser": [1417.015], + + "flex-pod2:stable/euphrates": [1370.23], + + "huawei-pod12:stable/euphrates": [1300.12] + +} diff --git a/docs/release/results/euphrates_fraser_comparsion.rst b/docs/release/results/euphrates_fraser_comparsion.rst deleted file mode 100644 index 222dc8bb0..000000000 --- a/docs/release/results/euphrates_fraser_comparsion.rst +++ /dev/null @@ -1,8 +0,0 @@ -.. This work is licensed under a Creative Commons Attribution 4.0 International -.. License. -.. http://creativecommons.org/licenses/by/4.0 - -======================================================= -Test results analysis for Euphrates and Fraser releases -======================================================= - diff --git a/docs/release/results/images/tc002_pod_fraser.png b/docs/release/results/images/tc002_pod_fraser.png Binary files differnew file mode 100644 index 000000000..797dc3136 --- /dev/null +++ b/docs/release/results/images/tc002_pod_fraser.png diff --git a/docs/release/results/images/tc002_scenario_fraser.png b/docs/release/results/images/tc002_scenario_fraser.png Binary files differnew file mode 100644 index 000000000..ff42e6516 --- /dev/null +++ b/docs/release/results/images/tc002_scenario_fraser.png diff --git a/docs/release/results/images/tc010_pod_fraser.png b/docs/release/results/images/tc010_pod_fraser.png Binary files differnew file mode 100644 index 000000000..23367d34a --- /dev/null +++ b/docs/release/results/images/tc010_pod_fraser.png diff --git a/docs/release/results/images/tc010_scenario_fraser.png b/docs/release/results/images/tc010_scenario_fraser.png Binary files differnew file mode 100644 index 000000000..a481a595f --- /dev/null +++ b/docs/release/results/images/tc010_scenario_fraser.png diff --git a/docs/release/results/images/tc011_pod_fraser.png b/docs/release/results/images/tc011_pod_fraser.png Binary files differnew file mode 100644 index 000000000..82dc9c763 --- /dev/null +++ b/docs/release/results/images/tc011_pod_fraser.png diff --git a/docs/release/results/images/tc011_scenario_fraser.png b/docs/release/results/images/tc011_scenario_fraser.png Binary files differnew file mode 100644 index 000000000..226d0b856 --- /dev/null +++ b/docs/release/results/images/tc011_scenario_fraser.png diff --git a/docs/release/results/images/tc012_pod_fraser.png b/docs/release/results/images/tc012_pod_fraser.png Binary files differnew file mode 100644 index 000000000..66e79be85 --- /dev/null +++ b/docs/release/results/images/tc012_pod_fraser.png diff --git a/docs/release/results/images/tc012_scenario_fraser.png b/docs/release/results/images/tc012_scenario_fraser.png Binary files differnew file mode 100644 index 000000000..4ef44119a --- /dev/null +++ b/docs/release/results/images/tc012_scenario_fraser.png diff --git a/docs/release/results/images/tc014_pod_fraseer.png b/docs/release/results/images/tc014_pod_fraseer.png Binary files differnew file mode 100644 index 000000000..697201d76 --- /dev/null +++ b/docs/release/results/images/tc014_pod_fraseer.png diff --git a/docs/release/results/images/tc014_scenario_fraser.png b/docs/release/results/images/tc014_scenario_fraser.png Binary files differnew file mode 100644 index 000000000..f7865dcdc --- /dev/null +++ b/docs/release/results/images/tc014_scenario_fraser.png diff --git a/docs/release/results/images/tc069_pod_fraser.png b/docs/release/results/images/tc069_pod_fraser.png Binary files differnew file mode 100644 index 000000000..1cba192d7 --- /dev/null +++ b/docs/release/results/images/tc069_pod_fraser.png diff --git a/docs/release/results/images/tc069_scenario_fraser.png b/docs/release/results/images/tc069_scenario_fraser.png Binary files differnew file mode 100644 index 000000000..f988b90c6 --- /dev/null +++ b/docs/release/results/images/tc069_scenario_fraser.png diff --git a/docs/release/results/images/tc082_pod_fraser.png b/docs/release/results/images/tc082_pod_fraser.png Binary files differnew file mode 100644 index 000000000..d54ab901a --- /dev/null +++ b/docs/release/results/images/tc082_pod_fraser.png diff --git a/docs/release/results/images/tc083_pod_fraser.png b/docs/release/results/images/tc083_pod_fraser.png Binary files differnew file mode 100644 index 000000000..942cc2074 --- /dev/null +++ b/docs/release/results/images/tc083_pod_fraser.png diff --git a/docs/release/results/index.rst b/docs/release/results/index.rst index 3ec9e1cff..63445fd1a 100644 --- a/docs/release/results/index.rst +++ b/docs/release/results/index.rst @@ -14,4 +14,4 @@ Yardstick test results .. include:: ./overview.rst .. include:: ./results.rst -.. include:: ./euphrates_fraser_comparsion.rst +.. include:: ./euphrates_fraser_comparison.rst diff --git a/docs/release/results/results.rst b/docs/release/results/results.rst index c75f5ae94..0ed92f867 100644 --- a/docs/release/results/results.rst +++ b/docs/release/results/results.rst @@ -23,6 +23,7 @@ Scenario Results The following documents contain results of Yardstick test cases executed on OPNFV labs, triggered by OPNFV CI pipeline, documented per test case. +For hardware details of OPNFV labs, please visit: https://wiki.opnfv.org/display/pharos/Community+Labs .. toctree:: :maxdepth: 1 @@ -38,6 +39,7 @@ OPNFV labs, triggered by OPNFV CI pipeline, documented per test case. Test results of executed tests are avilable in Dashboard_ and logs in Jenkins_. +Test results for Fraser release are collected from April 10, 2018 to May 13, 2018. Feature Test Results ==================== diff --git a/docs/release/results/tc002-network-latency.rst b/docs/release/results/tc002-network-latency.rst index 722423473..064983bec 100644 --- a/docs/release/results/tc002-network-latency.rst +++ b/docs/release/results/tc002-network-latency.rst @@ -315,3 +315,211 @@ The influence of the POD Fraser release -------------- + +Test results per scenario and pod (lower is better): + +{ + + "os-odl_l3-nofeature-ha:huawei-pod2:compass": [0.42], + + "os-odl-sfc-ha:huawei-pod2:compass": [0.557], + + "os-nosdn-ovs-ha:ericsson-pod1:fuel": [0.5765], + + "os-nosdn-kvm-ha:huawei-pod2:compass": [0.582], + + "os-odl-bgpvpn-ha:lf-pod1:apex": [0.678], + + "os-nosdn-nofeature-ha:lf-pod1:apex": [0.7075], + + "os-nosdn-calipso-noha:lf-pod1:apex": [0.713], + + "os-nosdn-nofeature-noha:lf-pod1:apex": [0.7155], + + "os-nosdn-bar-ha:lf-pod1:apex": [0.732], + + "os-nosdn-bar-noha:lf-pod1:apex": [0.7415], + + "os-odl-nofeature-noha:lf-pod1:apex": [0.7565], + + "os-nosdn-ovs-ha:arm-pod6:fuel": [0.8015], + + "os-nosdn-nofeature-ha:huawei-pod2:compass": [0.908], + + "os-odl-nofeature-ha:ericsson-pod1:fuel": [0.9165], + + "os-nosdn-bar-ha:huawei-pod2:compass": [0.969], + + "os-nosdn-ovs-noha:ericsson-virtual2:fuel": [0.9765], + + "os-nosdn-nofeature-noha:huawei-pod12:joid": [1.0245], + + "os-nosdn-nofeature-ha:huawei-pod12:joid": [1.0495], + + "os-odl-sfc-noha:huawei-virtual4:compass": [1.1645], + + "os-nosdn-nofeature-ha:lf-pod2:fuel": [1.206], + + "os-odl-sfc-noha:huawei-virtual3:compass": [1.236], + + "os-nosdn-ovs-noha:ericsson-virtual4:fuel": [1.241], + + "os-nosdn-nofeature-ha:zte-pod2:daisy": [1.2805], + + "os-odl-nofeature-ha:lf-pod2:fuel": [1.286], + + "os-odl_l3-nofeature-noha:huawei-virtual3:compass": [1.299], + + "os-odl-sfc-ha:huawei-virtual4:compass": [1.305], + + "os-odl_l3-nofeature-noha:huawei-virtual4:compass": [1.309], + + "os-nosdn-kvm-noha:huawei-virtual4:compass": [1.314], + + "os-nosdn-nofeature-noha:huawei-virtual4:compass": [1.431], + + "os-nosdn-nofeature-ha:ericsson-pod1:fuel": [1.457], + + "os-odl-nofeature-ha:zte-pod2:daisy": [1.517], + + "os-nosdn-kvm-noha:huawei-virtual3:compass": [1.576], + + "os-nosdn-nofeature-noha:huawei-virtual3:compass": [1.592], + + "os-odl-nofeature-ha:arm-pod5:fuel": [1.714], + + "os-nosdn-nofeature-noha:intel-pod18:joid": [1.809], + + "os-nosdn-bar-noha:huawei-virtual4:compass": [1.81], + + "os-nosdn-nofeature-ha:intel-pod18:joid": [1.8505], + + "os-nosdn-nofeature-ha:huawei-virtual4:compass": [1.8895], + + "os-nosdn-nofeature-ha:huawei-virtual3:compass": [1.909], + + "os-odl_l3-nofeature-ha:huawei-virtual4:compass": [1.925], + + "os-nosdn-nofeature-noha:huawei-virtual2:compass": [1.964], + + "os-nosdn-openbaton-ha:intel-pod18:joid": [1.9755], + + "os-nosdn-nofeature-ha:huawei-virtual1:compass": [1.9765], + + "os-nosdn-bar-noha:huawei-virtual3:compass": [1.9915], + + "os-odl_l3-nofeature-ha:huawei-virtual3:compass": [1.9925], + + "os-nosdn-kvm-ha:huawei-virtual4:compass": [2.0265], + + "os-odl-nofeature-ha:arm-pod6:fuel": [2.106], + + "os-odl-sfc-ha:huawei-virtual3:compass": [2.124], + + "os-nosdn-kvm-ha:huawei-virtual3:compass": [2.185], + + "os-nosdn-nofeature-ha:arm-pod6:fuel": [2.281], + + "os-nosdn-bar-ha:huawei-virtual4:compass": [2.432], + + "os-odl-nofeature-noha:ericsson-virtual4:fuel": [2.483], + + "os-nosdn-bar-ha:huawei-virtual3:compass": [2.524], + + "os-nosdn-nofeature-noha:ericsson-virtual3:fuel": [3.9175], + + "os-odl-nofeature-noha:ericsson-virtual2:fuel": [4.338], + + "os-nosdn-nofeature-noha:ericsson-virtual2:fuel": [4.641] + +} + + +The influence of the scenario +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. image:: images/tc002_scenario_fraser.png + :width: 800px + :alt: TC002 influence of scenario + +{ + + "os-odl-bgpvpn-ha": [0.678], + + "os-nosdn-calipso-noha": [0.713], + + "os-nosdn-ovs-ha": [0.7245], + + "os-odl_l3-nofeature-ha": [0.7435], + + "os-odl-sfc-ha": [0.796], + + "os-nosdn-kvm-ha": [1.059], + + "os-nosdn-bar-ha": [1.083], + + "os-nosdn-ovs-noha": [1.09], + + "os-odl-sfc-noha": [1.196], + + "os-nosdn-nofeature-noha": [1.26], + + "os-nosdn-nofeature-ha": [1.291], + + "os-odl_l3-nofeature-noha": [1.308], + + "os-nosdn-bar-noha": [1.4125], + + "os-nosdn-kvm-noha": [1.4475], + + "os-odl-nofeature-ha": [1.508], + + "os-odl-nofeature-noha": [1.914], + + "os-nosdn-openbaton-ha": [1.9755] + +} + + +The influence of the POD +^^^^^^^^^^^^^^^^^^^^^^^^ + +.. image:: images/tc002_pod_fraser.png + :width: 800px + :alt: TC002 influence of the POD + +{ + + "huawei-pod2": [0.677], + + "lf-pod1": [0.725], + + "ericsson-pod1": [0.9165], + + "huawei-pod12": [1.0465], + + "lf-pod2": [1.2325], + + "zte-pod2": [1.395], + + "ericsson-virtual4": [1.582], + + "huawei-virtual4": [1.697], + + "arm-pod5": [1.714], + + "huawei-virtual3": [1.716], + + "intel-pod18": [1.856], + + "huawei-virtual2": [1.964], + + "huawei-virtual1": [1.9765], + + "arm-pod6": [2.209], + + "ericsson-virtual3": [3.9175], + + "ericsson-virtual2": [4.004] + +} diff --git a/docs/release/results/tc010-memory-read-latency.rst b/docs/release/results/tc010-memory-read-latency.rst index 9a296b7a0..81559d647 100644 --- a/docs/release/results/tc010-memory-read-latency.rst +++ b/docs/release/results/tc010-memory-read-latency.rst @@ -297,3 +297,214 @@ The influence of the POD Fraser release -------------- + +Test results per scenario and pod (lower is better): + +{ + + "os-odl-nofeature-ha:ericsson-pod1:fuel": [6.8675], + + "os-nosdn-nofeature-noha:intel-pod18:joid": [6.991], + + "os-nosdn-openbaton-ha:intel-pod18:joid": [7.5535], + + "os-nosdn-nofeature-ha:intel-pod18:joid": [7.571], + "os-nosdn-ovs-ha:ericsson-pod1:fuel": [7.635], + + "os-nosdn-nofeature-ha:zte-pod2:daisy": [8.153], + + "os-odl-nofeature-ha:zte-pod2:daisy": [8.1935], + + "os-nosdn-bar-ha:huawei-pod2:compass": [9.1715], + + "os-odl-sfc-ha:huawei-pod2:compass": [9.1875], + + "os-odl_l3-nofeature-ha:huawei-pod2:compass": [9.241], + + "os-nosdn-nofeature-ha:huawei-pod2:compass": [9.255], + + "os-nosdn-kvm-ha:huawei-pod2:compass": [9.388], + + "os-nosdn-nofeature-noha:huawei-virtual4:compass": [9.5825], + + "os-nosdn-nofeature-noha:huawei-pod12:joid": [9.5875], + + "os-nosdn-nofeature-ha:huawei-pod12:joid": [9.6345], + + "os-odl-sfc-noha:huawei-virtual4:compass": [9.6535], + + "os-nosdn-nofeature-noha:ericsson-virtual2:fuel": [9.743], + + "os-odl-sfc-noha:huawei-virtual3:compass": [9.82], + + "os-odl-nofeature-noha:ericsson-virtual2:fuel": [9.8715], + + "os-odl_l3-nofeature-noha:huawei-virtual3:compass": [9.982], + + "os-nosdn-bar-noha:huawei-virtual4:compass": [10.0195], + + "os-odl_l3-nofeature-noha:huawei-virtual4:compass": [10.1285], + + "os-nosdn-nofeature-noha:huawei-virtual3:compass": [10.1335], + + "os-nosdn-nofeature-noha:huawei-virtual2:compass": [10.22], + + "os-nosdn-bar-noha:huawei-virtual3:compass": [10.2845], + + "os-nosdn-ovs-noha:ericsson-virtual4:fuel": [10.4185], + + "os-nosdn-ovs-noha:ericsson-virtual2:fuel": [10.4555], + + "os-nosdn-kvm-noha:huawei-virtual3:compass": [10.5635], + + "os-nosdn-kvm-noha:huawei-virtual4:compass": [10.6515], + + "os-nosdn-nofeature-noha:ericsson-virtual3:fuel": [10.9355], + + "os-odl-nofeature-noha:ericsson-virtual4:fuel": [11.2015], + + "os-odl_l3-nofeature-ha:huawei-virtual3:compass": [12.984], + + "os-nosdn-bar-ha:huawei-virtual3:compass": [13.306], + + "os-nosdn-nofeature-ha:huawei-virtual3:compass": [13.721], + + "os-nosdn-bar-ha:huawei-virtual4:compass": [14.133], + + "os-nosdn-nofeature-ha:ericsson-pod1:fuel": [14.158], + + "os-odl_l3-nofeature-ha:huawei-virtual4:compass": [14.375], + + "os-nosdn-nofeature-ha:huawei-virtual4:compass": [14.396], + + "os-nosdn-kvm-ha:huawei-virtual4:compass": [14.9375], + + "os-odl-sfc-ha:huawei-virtual3:compass": [14.957], + + "os-nosdn-calipso-noha:lf-pod1:apex": [16.3445], + + "os-nosdn-ovs-ha:lf-pod2:fuel": [16.478], + + "os-nosdn-nofeature-ha:lf-pod2:fuel": [16.4895], + + "os-odl-nofeature-noha:lf-pod1:apex": [16.55], + + "os-nosdn-nofeature-noha:lf-pod1:apex": [16.5665], + + "os-odl-sfc-noha:lf-pod1:apex": [16.598], + + "os-ovn-nofeature-noha:lf-pod1:apex": [16.805], + + "os-odl-nofeature-ha:lf-pod1:apex": [16.9095], + + "os-nosdn-bar-ha:lf-pod1:apex": [17.494], + + "os-nosdn-bar-noha:lf-pod1:apex": [17.4995], + + "os-nosdn-nofeature-ha:lf-pod1:apex": [18.094], + + "os-odl-nofeature-ha:arm-pod5:fuel": [18.744], + + "os-nosdn-nofeature-ha:huawei-virtual1:compass": [19.8235], + + "os-odl-nofeature-ha:lf-pod2:fuel": [20.758], + + "os-nosdn-kvm-ha:huawei-virtual3:compass": [26.5245], + + "os-nosdn-nofeature-ha:arm-pod6:fuel": [55.667], + + "os-odl-nofeature-ha:arm-pod6:fuel": [56.175], + + "os-nosdn-ovs-ha:arm-pod6:fuel": [57.86] + +} + + +The influence of the scenario +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. image:: images/tc010_scenario_fraser.png + :width: 800px + :alt: TC010 influence of scenario + +{ + + "os-nosdn-openbaton-ha": [7.5535], + + "os-odl-nofeature-ha": [8.2535], + + "os-odl-sfc-ha": [9.251], + + "os-nosdn-nofeature-ha": [9.464], + + "os-odl-sfc-noha": [9.8265], + + "os-odl_l3-nofeature-ha": [9.836], + + "os-odl_l3-nofeature-noha": [10.0565], + + "os-nosdn-nofeature-noha": [10.079], + + "os-nosdn-kvm-ha": [10.418], + + "os-nosdn-ovs-noha": [10.43], + + "os-nosdn-kvm-noha": [10.603], + + "os-nosdn-bar-noha": [11.067], + + "os-nosdn-bar-ha": [13.911], + + "os-odl-nofeature-noha": [14.046], + + "os-nosdn-calipso-noha": [16.3445], + + "os-nosdn-ovs-ha": [16.478], + + "os-ovn-nofeature-noha": [16.805] + +} + + +The influence of the POD +^^^^^^^^^^^^^^^^^^^^^^^^ + +.. image:: images/tc010_pod_fraser.png + :width: 800px + :alt: TC010 influence of the POD + +{ + + "ericsson-pod1": [7.0645], + + "intel-pod18": [7.4465], + + "zte-pod2": [8.1865], + + "huawei-pod2": [9.236], + + "huawei-pod12": [9.615], + + "ericsson-virtual2": [9.8925], + + "huawei-virtual2": [10.22], + + "ericsson-virtual4": [10.5465], + + "ericsson-virtual3": [10.9355], + + "huawei-virtual3": [10.95], + + "huawei-virtual4": [11.557], + + "lf-pod2": [16.5595], + + "lf-pod1": [16.8395], + + "arm-pod5": [18.744], + + "huawei-virtual1": [19.8235], + + "arm-pod6": [55.804] + +} diff --git a/docs/release/results/tc011-packet-delay-variation.rst b/docs/release/results/tc011-packet-delay-variation.rst index b07ea8980..f255b50ca 100644 --- a/docs/release/results/tc011-packet-delay-variation.rst +++ b/docs/release/results/tc011-packet-delay-variation.rst @@ -260,3 +260,173 @@ The influence of the POD Fraser release -------------- + +Test results per scenario and pod (lower is better): + +{ + + "os-nosdn-nofeature-ha:arm-pod6:fuel": [1], + + "os-nosdn-nofeature-ha:ericsson-pod1:fuel": [1], + + "os-nosdn-nofeature-ha:lf-pod2:fuel": [1], + + "os-nosdn-nofeature-noha:ericsson-virtual2:fuel": [1], + + "os-nosdn-nofeature-noha:ericsson-virtual3:fuel": [1], + + "os-ovn-nofeature-noha:lf-pod1:apex": [1511.5], + + "os-nosdn-kvm-noha:huawei-virtual3:compass": [2996], + + "os-nosdn-bar-ha:huawei-virtual4:compass": [2997], + + "os-nosdn-bar-noha:huawei-virtual4:compass": [2997], + + "os-nosdn-kvm-ha:huawei-virtual4:compass": [2997], + + "os-nosdn-nofeature-ha:huawei-virtual1:compass": [2997], + + "os-nosdn-nofeature-ha:huawei-virtual3:compass": [2997], + + "os-nosdn-nofeature-ha:huawei-virtual4:compass": [2997], + + "os-odl-sfc-ha:huawei-virtual3:compass": [2997], + + "os-odl_l3-nofeature-ha:huawei-virtual3:compass": [2997], + + "os-odl_l3-nofeature-noha:huawei-virtual3:compass": [3000], + + "os-odl_l3-nofeature-ha:huawei-virtual4:compass": [3003], + + "os-nosdn-bar-noha:huawei-virtual3:compass": [3011], + + "os-nosdn-bar-ha:huawei-virtual3:compass": [3015.5], + + "os-nosdn-kvm-noha:huawei-virtual4:compass": [3019], + + "os-nosdn-nofeature-noha:huawei-virtual4:compass": [3021], + + "os-odl-sfc-ha:huawei-virtual4:compass": [3021], + + "os-nosdn-bar-ha:huawei-pod2:compass": [3022], + + "os-nosdn-bar-ha:lf-pod1:apex": [3022], + + "os-nosdn-bar-noha:lf-pod1:apex": [3022], + + "os-nosdn-calipso-noha:lf-pod1:apex": [3022], + + "os-nosdn-kvm-ha:huawei-pod2:compass": [3022], + + "os-nosdn-nofeature-ha:huawei-pod12:joid": [3022], + + "os-nosdn-nofeature-ha:huawei-pod2:compass": [3022], + + "os-nosdn-nofeature-ha:intel-pod18:joid": [3022], + + "os-nosdn-nofeature-ha:lf-pod1:apex": [3022], + + "os-nosdn-nofeature-ha:zte-pod2:daisy": [3022], + + "os-nosdn-nofeature-noha:huawei-pod12:joid": [3022], + + "os-nosdn-nofeature-noha:intel-pod18:joid": [3022], + + "os-nosdn-nofeature-noha:lf-pod1:apex": [3022], + + "os-nosdn-openbaton-ha:intel-pod18:joid": [3022], + + "os-odl-sfc-ha:huawei-pod2:compass": [3022], + + "os-odl_l3-nofeature-ha:huawei-pod2:compass": [3022], + + "os-odl_l3-nofeature-noha:huawei-virtual4:compass": [3022], + + "os-odl-sfc-noha:huawei-virtual4:compass": [3022.5], + + "os-nosdn-nofeature-noha:huawei-virtual3:compass": [3023], + + "os-odl-sfc-noha:huawei-virtual3:compass": [3023], + + "os-nosdn-nofeature-noha:huawei-virtual2:compass": [3025] + +} + + +The influence of the scenario +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. image:: images/tc011_scenario_fraser.png + :width: 800px + :alt: TC011 influence of scenario + +{ + + "os-ovn-nofeature-noha": [1511.5], + + "os-nosdn-kvm-noha": [2997], + + "os-odl-sfc-ha": [3021], + + "os-nosdn-bar-ha": [3022], + + "os-nosdn-bar-noha": [3022], + + "os-nosdn-calipso-noha": [3022], + + "os-nosdn-kvm-ha": [3022], + + "os-nosdn-nofeature-ha": [3022], + + "os-nosdn-nofeature-noha": [3022], + + "os-nosdn-openbaton-ha": [3022], + + "os-odl_l3-nofeature-ha": [3022], + + "os-odl_l3-nofeature-noha": [3022], + + "os-odl-sfc-noha": [3023] + +} + + +The influence of the POD +^^^^^^^^^^^^^^^^^^^^^^^^ + +.. image:: images/tc011_pod_fraser.png + :width: 800px + :alt: TC011 influence of the POD + +{ + + "arm-pod6": [1], + + "ericsson-pod1": [1], + + "ericsson-virtual2": [1], + + "ericsson-virtual3": [1], + + "lf-pod2": [1], + + "huawei-virtual1": [2997], + + "huawei-virtual3": [2999], + + "huawei-virtual4": [3002], + + "huawei-pod12": [3022], + + "huawei-pod2": [3022], + + "intel-pod18": [3022], + + "lf-pod1": [3022], + + "zte-pod2": [3022], + + "huawei-virtual2": [3025] + +} diff --git a/docs/release/results/tc012-memory-read-write-bandwidth.rst b/docs/release/results/tc012-memory-read-write-bandwidth.rst index c28eb1f3c..71d69cde9 100644 --- a/docs/release/results/tc012-memory-read-write-bandwidth.rst +++ b/docs/release/results/tc012-memory-read-write-bandwidth.rst @@ -297,3 +297,217 @@ The influence of the POD Fraser release -------------- + +Test results per scenario and pod (higher is better): + +{ + + "os-nosdn-nofeature-ha:lf-pod2:fuel": [21421.795], + + "os-odl-sfc-noha:lf-pod1:apex": [21075], + + "os-odl-sfc-ha:lf-pod1:apex": [21017.44], + + "os-nosdn-bar-noha:lf-pod1:apex": [20991.46], + + "os-nosdn-bar-ha:lf-pod1:apex": [20812.405], + + "os-ovn-nofeature-noha:lf-pod1:apex": [20694.035], + + "os-nosdn-nofeature-noha:lf-pod1:apex": [20672.765], + + "os-odl-nofeature-ha:lf-pod2:fuel": [20269.65], + + "os-nosdn-calipso-noha:lf-pod1:apex": [20186.32], + + "os-odl-nofeature-noha:lf-pod1:apex": [19959.915], + + "os-nosdn-ovs-ha:lf-pod2:fuel": [19719.38], + + "os-odl-nofeature-ha:lf-pod1:apex": [19654.505], + + "os-nosdn-nofeature-ha:lf-pod1:apex": [19391.145], + + "os-nosdn-nofeature-noha:intel-pod18:joid": [19378.64], + + "os-odl-nofeature-ha:ericsson-pod1:fuel": [19103.43], + + "os-nosdn-nofeature-ha:intel-pod18:joid": [18688.695], + + "os-nosdn-openbaton-ha:intel-pod18:joid": [18557.95], + + "os-nosdn-nofeature-ha:ericsson-pod1:fuel": [17088.61], + + "os-nosdn-ovs-ha:ericsson-pod1:fuel": [17040.78], + + "os-nosdn-ovs-noha:ericsson-virtual2:fuel": [16057.235], + + "os-odl-nofeature-noha:ericsson-virtual4:fuel": [15622.355], + + "os-nosdn-nofeature-noha:ericsson-virtual2:fuel": [15422.235], + + "os-odl-sfc-ha:huawei-pod2:compass": [15403.09], + + "os-odl-nofeature-noha:ericsson-virtual2:fuel": [15141.58], + + "os-nosdn-bar-ha:huawei-pod2:compass": [14922.37], + + "os-odl_l3-nofeature-ha:huawei-pod2:compass": [14864.195], + + "os-nosdn-nofeature-ha:huawei-pod2:compass": [14856.295], + + "os-nosdn-kvm-ha:huawei-pod2:compass": [14796.035], + + "os-odl-sfc-noha:huawei-virtual4:compass": [14484.375], + + "os-nosdn-nofeature-ha:huawei-pod12:joid": [14441.955], + + "os-odl-sfc-noha:huawei-virtual3:compass": [14373], + + "os-nosdn-nofeature-noha:huawei-virtual4:compass": [14330.44], + + "os-nosdn-ovs-noha:ericsson-virtual4:fuel": [14320.305], + + "os-odl_l3-nofeature-noha:huawei-virtual3:compass": [14253.715], + + "os-nosdn-nofeature-ha:huawei-virtual4:compass": [14203.655], + + "os-nosdn-nofeature-noha:huawei-virtual3:compass": [14179.93], + + "os-odl-nofeature-ha:zte-pod2:daisy": [14177.135], + + "os-nosdn-nofeature-ha:zte-pod2:daisy": [14150.825], + + "os-nosdn-nofeature-noha:huawei-pod12:joid": [14100.87], + + "os-nosdn-bar-noha:huawei-virtual4:compass": [14033.36], + + "os-odl_l3-nofeature-noha:huawei-virtual4:compass": [13963.73], + + "os-nosdn-kvm-noha:huawei-virtual3:compass": [13874.775], + + "os-nosdn-kvm-noha:huawei-virtual4:compass": [13805.65], + + "os-odl_l3-nofeature-ha:huawei-virtual3:compass": [13754.63], + + "os-nosdn-nofeature-noha:huawei-virtual2:compass": [13702.92], + + "os-nosdn-bar-ha:huawei-virtual3:compass": [13638.115], + + "os-odl-sfc-ha:huawei-virtual3:compass": [13637.83], + + "os-odl_l3-nofeature-ha:huawei-virtual4:compass": [13635.66], + + "os-nosdn-bar-noha:huawei-virtual3:compass": [13635.58], + + "os-nosdn-bar-ha:huawei-virtual4:compass": [13544.95], + + "os-nosdn-nofeature-ha:huawei-virtual3:compass": [13514.27], + + "os-nosdn-nofeature-ha:huawei-virtual1:compass": [13496.45], + + "os-odl-sfc-ha:huawei-virtual4:compass": [13475.38], + + "os-nosdn-nofeature-noha:ericsson-virtual3:fuel": [12733.19], + + "os-nosdn-kvm-ha:huawei-virtual4:compass": [12682.805], + + "os-odl-nofeature-ha:arm-pod5:fuel": [4326.11], + + "os-nosdn-nofeature-ha:arm-pod6:fuel": [3824.13], + + "os-odl-nofeature-ha:arm-pod6:fuel": [3797.795], + + "os-nosdn-ovs-ha:arm-pod6:fuel": [3749.91] + +} + + +The influence of the scenario +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. image:: images/tc012_scenario_fraser.png + :width: 800px + :alt: TC012 influence of scenario + +{ + + "os-ovn-nofeature-noha": [20694.035], + + "os-nosdn-calipso-noha": [20186.32], + + "os-nosdn-openbaton-ha": [18557.95], + + "os-nosdn-ovs-ha": [17048.17], + + "os-odl-nofeature-noha": [16191.125], + + "os-nosdn-ovs-noha": [15790.32], + + "os-nosdn-bar-ha": [14833.97], + + "os-odl-sfc-ha": [14828.72], + + "os-odl_l3-nofeature-ha": [14801.25], + + "os-nosdn-kvm-ha": [14700.1], + + "os-nosdn-nofeature-ha": [14610.48], + + "os-nosdn-nofeature-noha": [14555.975], + + "os-odl-sfc-noha": [14508.14], + + "os-nosdn-bar-noha": [14395.22], + + "os-odl-nofeature-ha": [14231.245], + + "os-odl_l3-nofeature-noha": [14161.58], + + "os-nosdn-kvm-noha": [13845.685] + +} + + +The influence of the POD +^^^^^^^^^^^^^^^^^^^^^^^^ + +.. image:: images/tc012_pod_fraser.png + :width: 800px + :alt: TC012 influence of the POD + +{ + + "lf-pod1": [20552.9], + + "lf-pod2": [20058.925], + + "ericsson-pod1": [18930.78], + + "intel-pod18": [18757.545], + + "ericsson-virtual4": [15389.465], + + "ericsson-virtual2": [15343.79], + + "huawei-pod2": [14870.78], + + "zte-pod2": [14157.99], + + "huawei-pod12": [14126.99], + + "huawei-virtual3": [13929.67], + + "huawei-virtual4": [13847.155], + + "huawei-virtual2": [13702.92], + + "huawei-virtual1": [13496.45], + + "ericsson-virtual3": [12733.19], + + "arm-pod5": [4326.11], + + "arm-pod6": [3809.885] + +} diff --git a/docs/release/results/tc014-cpu-processing-speed.rst b/docs/release/results/tc014-cpu-processing-speed.rst index 34d4ad0f9..a2eeb6302 100644 --- a/docs/release/results/tc014-cpu-processing-speed.rst +++ b/docs/release/results/tc014-cpu-processing-speed.rst @@ -296,3 +296,217 @@ The influence of the POD Fraser release -------------- + +Test results per scenario and pod (higher is better): + +{ + + "os-nosdn-nofeature-ha:lf-pod2:fuel": [3747.3], + + "os-nosdn-calipso-noha:lf-pod1:apex": [3727.2], + + "os-odl-nofeature-ha:lf-pod1:apex": [3726.5], + + "os-ovn-nofeature-noha:lf-pod1:apex": [3723.8], + + "os-odl-nofeature-noha:lf-pod1:apex": [3718.9], + + "os-nosdn-nofeature-noha:lf-pod1:apex": [3717.75], + + "os-nosdn-nofeature-ha:lf-pod1:apex": [3706.5], + + "os-odl-nofeature-ha:lf-pod2:fuel": [3704.9], + + "os-nosdn-ovs-ha:lf-pod2:fuel": [3687.7], + + "os-nosdn-bar-noha:lf-pod1:apex": [3635.4], + + "os-nosdn-bar-ha:lf-pod1:apex": [3632.55], + + "os-odl-sfc-noha:lf-pod1:apex": [3569], + + "os-nosdn-nofeature-noha:intel-pod18:joid": [3432.1], + + "os-odl-nofeature-ha:ericsson-pod1:fuel": [3133.85], + + "os-nosdn-ovs-ha:ericsson-pod1:fuel": [3079.8], + + "os-nosdn-nofeature-ha:intel-pod18:joid": [3074.75], + + "os-nosdn-openbaton-ha:intel-pod18:joid": [2976.2], + + "os-nosdn-nofeature-ha:zte-pod2:daisy": [2910.95], + + "os-odl-nofeature-ha:zte-pod2:daisy": [2801.1], + + "os-nosdn-ovs-noha:ericsson-virtual2:fuel": [2603], + + "os-odl-nofeature-noha:ericsson-virtual2:fuel": [2559.7], + + "os-nosdn-nofeature-noha:ericsson-virtual2:fuel": [2539.1], + + "os-odl_l3-nofeature-ha:huawei-pod2:compass": [2530.5], + + "os-nosdn-nofeature-ha:huawei-pod2:compass": [2529.4], + + "os-odl-sfc-ha:huawei-pod2:compass": [2528.9], + + "os-odl-nofeature-noha:ericsson-virtual4:fuel": [2527.8], + + "os-nosdn-bar-ha:huawei-pod2:compass": [2527.4], + + "os-nosdn-kvm-ha:huawei-pod2:compass": [2517.8], + + "os-nosdn-nofeature-noha:huawei-virtual4:compass": [2472.4], + + "os-nosdn-nofeature-ha:huawei-virtual4:compass": [2469.1], + + "os-odl-sfc-noha:huawei-virtual3:compass": [2452.05], + + "os-odl-sfc-noha:huawei-virtual4:compass": [2438.7], + + "os-odl_l3-nofeature-noha:huawei-virtual3:compass": [2418.4], + + "os-nosdn-ovs-noha:ericsson-virtual4:fuel": [2404.35], + + "os-nosdn-kvm-noha:huawei-virtual3:compass": [2391], + + "os-nosdn-kvm-noha:huawei-virtual4:compass": [2376.75], + + "os-odl_l3-nofeature-noha:huawei-virtual4:compass": [2376.2], + + "os-nosdn-nofeature-noha:huawei-virtual3:compass": [2359.45], + + "os-nosdn-bar-noha:huawei-virtual4:compass": [2353.3], + + "os-odl-sfc-ha:huawei-virtual3:compass": [2351.9], + + "os-nosdn-bar-ha:huawei-virtual3:compass": [2339.4], + + "os-odl-sfc-ha:huawei-virtual4:compass": [2335.6], + + "os-nosdn-bar-ha:huawei-virtual4:compass": [2328], + + "os-odl_l3-nofeature-ha:huawei-virtual3:compass": [2324.5], + + "os-nosdn-bar-noha:huawei-virtual3:compass": [2317.3], + + "os-nosdn-nofeature-ha:huawei-virtual3:compass": [2313.95], + + "os-odl_l3-nofeature-ha:huawei-virtual4:compass": [2308.1], + + "os-nosdn-nofeature-noha:huawei-virtual2:compass": [2299.3], + + "os-nosdn-kvm-ha:huawei-virtual4:compass": [2250.4], + + "os-nosdn-nofeature-noha:huawei-pod12:joid": [2229.7], + + "os-nosdn-nofeature-ha:huawei-pod12:joid": [2228.8], + + "os-nosdn-nofeature-ha:huawei-virtual1:compass": [2171.3], + + "os-nosdn-nofeature-noha:ericsson-virtual3:fuel": [2104.8], + + "os-nosdn-nofeature-ha:ericsson-pod1:fuel": [1961.35], + + "os-nosdn-ovs-ha:arm-pod5:fuel": [1764.2], + + "os-odl-nofeature-ha:arm-pod5:fuel": [1730.95], + + "os-nosdn-ovs-ha:arm-pod6:fuel": [715.55], + + "os-odl-nofeature-ha:arm-pod6:fuel": [715.4], + + "os-nosdn-nofeature-ha:arm-pod6:fuel": [715.25] + +} + + +The influence of the scenario +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. image:: images/tc014_scenario_fraser.png + :width: 800px + :alt: TC014 influence of scenario + +{ + + "os-nosdn-calipso-noha": [3727.2], + + "os-ovn-nofeature-noha": [3723.8], + + "os-odl-nofeature-noha": [3128.05], + + "os-nosdn-openbaton-ha": [2976.2], + + "os-nosdn-ovs-ha": [2814.5], + + "os-odl-nofeature-ha": [2801.4], + + "os-nosdn-nofeature-ha": [2649.7], + + "os-nosdn-ovs-noha": [2587.3], + + "os-odl_l3-nofeature-ha": [2528.45], + + "os-odl-sfc-ha": [2527.6], + + "os-nosdn-bar-ha": [2526.55], + + "os-nosdn-kvm-ha": [2516.95], + + "os-odl-sfc-noha": [2453.65], + + "os-nosdn-bar-noha": [2447.7], + + "os-nosdn-nofeature-noha": [2443.85], + + "os-odl_l3-nofeature-noha": [2394.3], + + "os-nosdn-kvm-noha": [2379.7] + +} + + +The influence of the POD +^^^^^^^^^^^^^^^^^^^^^^^^ + +.. image:: images/tc014_pod_fraser.png + :width: 800px + :alt: TC014 influence of the POD + +{ + + "lf-pod2": [3737.6], + + "lf-pod1": [3702.7], + + "ericsson-pod1": [3131.6], + + "intel-pod18": [3098.1], + + "zte-pod2": [2831.4], + + "ericsson-virtual2": [2559.7], + + "huawei-pod2": [2528.9], + + "ericsson-virtual4": [2527.8], + + "huawei-virtual3": [2379.1], + + "huawei-virtual4": [2362.1], + + "huawei-virtual2": [2299.3], + + "huawei-pod12": [2229], + + "huawei-virtual1": [2171.3], + + "ericsson-virtual3": [2104.8], + + "arm-pod5": [1764.2], + + "arm-pod6": [715.4] + +} diff --git a/docs/release/results/tc069-memory-write-bandwidth.rst b/docs/release/results/tc069-memory-write-bandwidth.rst index 06e2ec922..4cd3be3b0 100644 --- a/docs/release/results/tc069-memory-write-bandwidth.rst +++ b/docs/release/results/tc069-memory-write-bandwidth.rst @@ -298,3 +298,219 @@ The influence of the POD Fraser release -------------- + +Test results per scenario and pod (higher is better): + +{ + + "os-nosdn-nofeature-noha:intel-pod18:joid": [18382.49], + + "os-nosdn-openbaton-ha:intel-pod18:joid": [16774.52], + + "os-nosdn-nofeature-ha:intel-pod18:joid": [16680.305], + + "os-nosdn-ovs-ha:arm-pod6:fuel": [11925.22], + + "os-nosdn-nofeature-ha:arm-pod6:fuel": [11895.71], + + "os-odl-nofeature-ha:arm-pod6:fuel": [11880.7], + + "os-nosdn-nofeature-ha:ericsson-pod1:fuel": [9471.095], + + "os-odl-nofeature-ha:zte-pod2:daisy": [9375.33], + + "os-nosdn-nofeature-ha:zte-pod2:daisy": [9372.95], + + "os-odl-nofeature-ha:ericsson-pod1:fuel": [9174.36], + + "os-nosdn-nofeature-noha:huawei-pod12:joid": [9051.57], + + "os-nosdn-nofeature-ha:huawei-pod12:joid": [8894.74], + + "os-odl_l3-nofeature-ha:huawei-pod2:compass": [8857.23], + + "os-nosdn-nofeature-ha:huawei-pod2:compass": [8855.8], + + "os-nosdn-bar-ha:huawei-pod2:compass": [8840.94], + + "os-odl-sfc-ha:huawei-pod2:compass": [8826.23], + + "os-nosdn-nofeature-noha:huawei-virtual4:compass": [8039.48], + + "os-nosdn-nofeature-noha:huawei-virtual2:compass": [7670.21], + + "os-nosdn-ovs-ha:arm-pod5:fuel": [7590.9], + + "os-odl-sfc-noha:huawei-virtual4:compass": [7579.625], + + "os-nosdn-bar-noha:huawei-virtual3:compass": [7511.775], + + "os-odl-nofeature-ha:arm-pod5:fuel": [7475.16], + + "os-nosdn-bar-noha:huawei-virtual4:compass": [7435.08], + + "os-nosdn-nofeature-noha:ericsson-virtual2:fuel": [7426.79], + + "os-nosdn-nofeature-ha:huawei-virtual4:compass": [7362.8], + + "os-nosdn-kvm-noha:huawei-virtual4:compass": [7263.45], + + "os-nosdn-nofeature-noha:huawei-virtual3:compass": [7262.72], + + "os-odl_l3-nofeature-noha:huawei-virtual3:compass": [7241.07], + + "os-odl-nofeature-noha:ericsson-virtual2:fuel": [7219.21], + + "os-nosdn-kvm-noha:huawei-virtual3:compass": [7174.33], + + "os-odl-sfc-noha:huawei-virtual3:compass": [7170.795], + + "os-odl-nofeature-noha:lf-pod1:apex": [7158.335], + + "os-nosdn-kvm-ha:huawei-pod2:compass": [7122.45], + + "os-odl-sfc-ha:huawei-virtual4:compass": [7104.9], + + "os-nosdn-ovs-noha:ericsson-virtual2:fuel": [7044.37], + + "os-nosdn-bar-ha:huawei-virtual3:compass": [7011.075], + + "os-nosdn-ovs-ha:ericsson-pod1:fuel": [6950.28], + + "os-nosdn-ovs-noha:ericsson-virtual4:fuel": [6918.31], + + "os-nosdn-bar-ha:huawei-virtual4:compass": [6903.11], + + "os-nosdn-nofeature-ha:lf-pod2:fuel": [6880.98], + + "os-odl-sfc-ha:lf-pod1:apex": [6863.39], + + "os-odl_l3-nofeature-ha:huawei-virtual3:compass": [6851.54], + + "os-nosdn-nofeature-noha:lf-pod1:apex": [6834.75], + + "os-nosdn-calipso-noha:lf-pod1:apex": [6833.92], + + "os-nosdn-ovs-ha:lf-pod2:fuel": [6814.68], + + "os-ovn-nofeature-noha:lf-pod1:apex": [6809.44], + + "os-odl_l3-nofeature-ha:huawei-virtual4:compass": [6784.48], + + "os-nosdn-nofeature-ha:lf-pod1:apex": [6737.64], + + "os-nosdn-bar-noha:lf-pod1:apex": [6708.61], + + "os-nosdn-bar-ha:lf-pod1:apex": [6697.2], + + "os-odl-nofeature-ha:lf-pod1:apex": [6626.51], + + "os-odl-sfc-noha:lf-pod1:apex": [6609.57], + + "os-odl-sfc-ha:huawei-virtual3:compass": [6606.87], + + "os-odl_l3-nofeature-noha:huawei-virtual4:compass": [6547.39], + + "os-odl-nofeature-ha:lf-pod2:fuel": [6465.48], + + "os-odl-nofeature-noha:ericsson-virtual4:fuel": [6413], + + "os-nosdn-kvm-ha:huawei-virtual4:compass": [6409.075], + + "os-nosdn-nofeature-ha:huawei-virtual3:compass": [6128.79], + + "os-nosdn-nofeature-noha:ericsson-virtual3:fuel": [5835.59], + + "os-nosdn-nofeature-ha:huawei-virtual1:compass": [5617.12] + +} + + +The influence of the scenario +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. image:: images/tc069_scenario_fraser.png + :width: 800px + :alt: TC069 influence of scenario + +{ + + "os-nosdn-openbaton-ha": [16774.52], + + "os-odl-nofeature-ha": [9363.69], + + "os-nosdn-nofeature-ha": [8878.01], + + "os-odl_l3-nofeature-ha": [8748.4], + + "os-odl-sfc-ha": [8708.045], + + "os-nosdn-nofeature-noha": [7426.79], + + "os-nosdn-kvm-noha": [7230.79], + + "os-odl-sfc-noha": [7224.11], + + "os-odl-nofeature-noha": [7187.84], + + "os-nosdn-ovs-noha": [7044.37], + + "os-nosdn-bar-ha": [6947.87], + + "os-odl_l3-nofeature-noha": [6895.96], + + "os-nosdn-kvm-ha": [6890.92], + + "os-nosdn-calipso-noha": [6833.92], + + "os-nosdn-ovs-ha": [6833.495], + + "os-nosdn-bar-noha": [6811.66], + + "os-ovn-nofeature-noha": [6809.44] + +} + + +The influence of the POD +^^^^^^^^^^^^^^^^^^^^^^^^ + +.. image:: images/tc069_pod_fraser.png + :width: 800px + :alt: TC069 influence of the POD + +{ + + "intel-pod18": [16939.24], + + "arm-pod6": [11895.71], + + "zte-pod2": [9375.33], + + "ericsson-pod1": [9140.42], + + "huawei-pod12": [8993.37], + + "huawei-pod2": [8794.01], + + "huawei-virtual2": [7670.21], + + "arm-pod5": [7479.32], + + "ericsson-virtual2": [7219.21], + + "huawei-virtual4": [7059.045], + + "huawei-virtual3": [7023.57], + + "lf-pod2": [6834.7], + + "lf-pod1": [6775.27], + + "ericsson-virtual4": [6522.86], + + "ericsson-virtual3": [5835.59], + + "huawei-virtual1": [5617.12] + +} diff --git a/docs/release/results/tc082-context-switches-under-load.rst b/docs/release/results/tc082-context-switches-under-load.rst index d8a9f5493..92bc69907 100644 --- a/docs/release/results/tc082-context-switches-under-load.rst +++ b/docs/release/results/tc082-context-switches-under-load.rst @@ -70,8 +70,6 @@ The influence of the scenario :width: 800px :alt: TC082 influence of scenario -the influence of the scenario - { "os-nosdn-nofeature-ha": [505], @@ -88,8 +86,6 @@ The influence of the POD :width: 800px :alt: TC082 influence of the POD -the influence of the POD - { "huawei-pod12": [316], @@ -127,3 +123,65 @@ the influence of the POD Fraser release -------------- + +Test results per scenario and pod (lower is better): + +{ + + "os-nosdn-nofeature-ha:zte-pod2:daisy": [306.5], + + "os-nosdn-nofeature-ha:lf-pod2:fuel": [337.5], + + "os-nosdn-nofeature-ha:intel-pod18:joid": [343.5], + + "os-nosdn-nofeature-ha:huawei-pod12:joid": [399], + + "os-nosdn-nofeature-ha:lf-pod1:apex": [454], + + "os-nosdn-nofeature-ha:huawei-pod2:compass": [544.5], + + "os-nosdn-nofeature-ha:huawei-virtual4:compass": [1138], + + "os-nosdn-nofeature-ha:ericsson-pod1:fuel": [1305], + + "os-nosdn-nofeature-ha:huawei-virtual3:compass": [1433], + + "os-nosdn-nofeature-ha:huawei-virtual1:compass": [1470], + + "os-nosdn-nofeature-ha:arm-pod6:fuel": [1738.5] + +} + + +The influence of the POD +^^^^^^^^^^^^^^^^^^^^^^^^ + +.. image:: images/tc082_pod_fraser.png + :width: 800px + :alt: TC082 influence of the POD + +{ + + "zte-pod2": [306.5], + + "lf-pod2": [337.5], + + "intel-pod18": [343.5], + + "huawei-pod12": [399], + + "lf-pod1": [454], + + "huawei-pod2": [544.5], + + "huawei-virtual4": [1138], + + "ericsson-pod1": [1305], + + "huawei-virtual3": [1433], + + "huawei-virtual1": [1470], + + "arm-pod6": [1738.5] + +} diff --git a/docs/release/results/tc083-network-throughput-between-vm.rst b/docs/release/results/tc083-network-throughput-between-vm.rst index f846571a5..0389eaafe 100644 --- a/docs/release/results/tc083-network-throughput-between-vm.rst +++ b/docs/release/results/tc083-network-throughput-between-vm.rst @@ -70,8 +70,6 @@ The influence of the scenario :width: 800px :alt: TC083 influence of scenario -the influence of the scenario - { "os-nosdn-nofeature-ha": [1109.12], @@ -88,8 +86,6 @@ The influence of the POD :width: 800px :alt: TC083 influence of the POD -the influence of the POD - { "lf-pod1": [2204.42], @@ -127,3 +123,65 @@ the influence of the POD Fraser release -------------- + +Test results per scenario and pod (higher is better): + +{ + + "os-nosdn-nofeature-ha:lf-pod2:fuel": [1893.39], + + "os-nosdn-nofeature-ha:zte-pod2:daisy": [1543.995], + + "os-nosdn-nofeature-ha:lf-pod1:apex": [1480.86], + + "os-nosdn-nofeature-ha:intel-pod18:joid": [1417.015], + + "os-nosdn-nofeature-ha:huawei-pod12:joid": [1028.55], + + "os-nosdn-nofeature-ha:huawei-pod2:compass": [1007.65], + + "os-nosdn-nofeature-ha:ericsson-pod1:fuel": [811.795], + + "os-nosdn-nofeature-ha:huawei-virtual4:compass": [552.95], + + "os-nosdn-nofeature-ha:arm-pod6:fuel": [227.655], + + "os-nosdn-nofeature-ha:huawei-virtual1:compass": [216.63], + + "os-nosdn-nofeature-ha:huawei-virtual3:compass": [59.255] + +} + + +The influence of the POD +^^^^^^^^^^^^^^^^^^^^^^^^ + +.. image:: images/tc083_pod_fraser.png + :width: 800px + :alt: TC083 influence of the POD + +{ + + "lf-pod2": [1893.39], + + "zte-pod2": [1543.995], + + "lf-pod1": [1480.86], + + "intel-pod18": [1417.015], + + "huawei-pod12": [1028.55], + + "huawei-pod2": [1007.65], + + "ericsson-pod1": [811.795], + + "huawei-virtual4": [552.95], + + "arm-pod6": [227.655], + + "huawei-virtual1": [216.63], + + "huawei-virtual3": [59.255] + +} diff --git a/docs/testing/developer/devguide/devguide.rst b/docs/testing/developer/devguide/devguide.rst index 04d5350be..91f2c2148 100755 --- a/docs/testing/developer/devguide/devguide.rst +++ b/docs/testing/developer/devguide/devguide.rst @@ -1,16 +1,42 @@ +.. + 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. + + Convention for heading levels in Yardstick documentation: + + ======= Heading 0 (reserved for the title in a document) + ------- Heading 1 + ~~~~~~~ Heading 2 + +++++++ Heading 3 + ''''''' Heading 4 + + Avoid deeper levels because they do not render well. + Introduction -============= +------------ -Yardstick is a project dealing with performance testing. Yardstick produces its own test cases but can also be considered as a framework to support feature project testing. +Yardstick is a project dealing with performance testing. Yardstick produces +its own test cases but can also be considered as a framework to support feature +project testing. -Yardstick developed a test API that can be used by any OPNFV project. Therefore there are many ways to contribute to Yardstick. +Yardstick developed a test API that can be used by any OPNFV project. Therefore +there are many ways to contribute to Yardstick. You can: * Develop new test cases * Review codes * Develop Yardstick API / framework -* Develop Yardstick grafana dashboards and Yardstick reporting page +* Develop Yardstick grafana dashboards and Yardstick reporting page * Write Yardstick documentation This developer guide describes how to interact with the Yardstick project. @@ -19,28 +45,30 @@ part is a list of “How to” to help you to join the Yardstick family whatever your field of interest is. Where can I find some help to start? --------------------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. _`user guide`: http://artifacts.opnfv.org/yardstick/danube/1.0/docs/stesting_user_userguide/index.html .. _`wiki page`: https://wiki.opnfv.org/display/yardstick/ This guide is made for you. You can have a look at the `user guide`_. There are also references on documentation, video tutorials, tips in the -project `wiki page`_. You can also directly contact us by mail with [Yardstick] prefix in the title at opnfv-tech-discuss@lists.opnfv.org or on the IRC chan #opnfv-yardstick. +project `wiki page`_. You can also directly contact us by mail with [Yardstick] +prefix in the subject at opnfv-tech-discuss@lists.opnfv.org or on the IRC chan +#opnfv-yardstick. Yardstick developer areas -========================== +------------------------- Yardstick framework --------------------- +~~~~~~~~~~~~~~~~~~~ -Yardstick can be considered as a framework. Yardstick is release as a docker +Yardstick can be considered as a framework. Yardstick is released as a docker file, including tools, scripts and a CLI to prepare the environement and run -tests. It simplifies the integration of external test suites in CI pipeline -and provide commodity tools to collect and display results. +tests. It simplifies the integration of external test suites in CI pipelines +and provides commodity tools to collect and display results. -Since Danube, test categories also known as tiers have been created to group +Since Danube, test categories (also known as tiers) have been created to group similar tests, provide consistant sub-lists and at the end optimize test duration for CI (see How To section). @@ -56,44 +84,54 @@ The tiers are: How Todos? -=========== +---------- How Yardstick works? ---------------------- +~~~~~~~~~~~~~~~~~~~~ The installation and configuration of the Yardstick is described in the `user guide`_. How to work with test cases? ----------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Sample Test cases ++++++++++++++++++ -**Sample Test cases** +Yardstick provides many sample test cases which are located at ``samples`` directory of repo. -Yardstick provides many sample test cases which are located at "samples" directory of repo. +Sample test cases are designed with the following goals: -Sample test cases are designed as following goals: +1. Helping user better understand Yardstick features (including new feature and + new test capacity). -1. Helping user better understand yardstick features(including new feature and new test capacity). +2. Helping developer to debug a new feature and test case before it is + offically released. -2. Helping developer to debug his new feature and test case before it is offical released. +3. Helping other developers understand and verify the new patch before the + patch is merged. -3. Helping other developers understand and verify the new patch before the patch merged. +Developers should upload their sample test cases as well when they are +uploading a new patch which is about the Yardstick new test case or new feature. -So developers should upload your sample test case as well when they are trying to upload a new patch which is about the yardstick new test case or new feature. +OPNFV Release Test cases +++++++++++++++++++++++++ -**OPNFV Release Test cases** +OPNFV Release test cases are located at ``yardstick/tests/opnfv/test_cases``. +These test cases are run by OPNFV CI jobs, which means these test cases should +be more mature than sample test cases. +OPNFV scenario owners can select related test cases and add them into the test +suites which represent their scenario. -OPNFV Release test cases which are located at "tests/opnfv/test_cases" of repo. -those test cases are runing by OPNFV CI jobs, It means those test cases should be more mature than sample test cases. -OPNFV scenario owners can select related test cases and add them into the test suites which is represent the scenario. - -**Test case Description File** +Test case Description File +++++++++++++++++++++++++++ This section will introduce the meaning of the Test case description file. -we will use ping.yaml as a example to show you how to understand the test case description file. -In this Yaml file, you can easily find it consists of two sections. One is “Scenarios”, the other is “Context”.:: +we will use ping.yaml as a example to show you how to understand the test case +description file. +This ``yaml`` file consists of two sections. One is ``scenarios``, the other +is ``context``.:: --- # Sample benchmark task config file @@ -150,18 +188,32 @@ In this Yaml file, you can easily find it consists of two sections. One is “Sc {% endif %} -"Contexts" section is the description of pre-condition of testing. As ping.yaml shown, you can configure the image, flavor , name ,affinity and network of Test VM(servers), with this section, you will get a pre-condition env for Testing. -Yardstick will automatic setup the stack which are described in this section. -In fact, yardstick use convert this section to heat template and setup the VMs by heat-client (Meanwhile, yardstick can support to convert this section to Kubernetes template to setup containers). - -Two Test VMs(athena and ares) are configured by keyword "servers". -"flavor" will determine how many vCPU, how much memory for test VMs. -As "yardstick-flavor" is a basic flavor which will be automatically created when you run command "yardstick env prepare". "yardstick-flavor" is "1 vCPU 1G RAM,3G Disk". -"image" is the image name of test VMs. if you use cirros.3.5.0, you need fill the username of this image into "user". the "policy" of placement of Test VMs have two values (affinity and availability). -"availability" means anti-affinity. In "network" section, you can configure which provide network and physical_network you want Test VMs use. -you may need to configure segmentation_id when your network is vlan. - -Moreover, you can configure your specific flavor as below, yardstick will setup the stack for you. :: +The ``contexts`` section is the description of pre-condition of testing. As +``ping.yaml`` shows, you can configure the image, flavor, name, affinity and +network of Test VM (servers), with this section, you will get a pre-condition +env for Testing. +Yardstick will automatically setup the stack which are described in this +section. +Yardstick converts this section to heat template and sets up the VMs with +heat-client (Yardstick can also support to convert this section to Kubernetes +template to setup containers). + +In the examples above, two Test VMs (athena and ares) are configured by +keyword ``servers``. +``flavor`` will determine how many vCPU, how much memory for test VMs. +As ``yardstick-flavor`` is a basic flavor which will be automatically created +when you run command ``yardstick env prepare``. ``yardstick-flavor`` is +``1 vCPU 1G RAM,3G Disk``. +``image`` is the image name of test VMs. If you use ``cirros.3.5.0``, you need +fill the username of this image into ``user``. +The ``policy`` of placement of Test VMs have two values (``affinity`` and +``availability``). ``availability`` means anti-affinity. +In the ``network`` section, you can configure which ``provider`` network and +``physical_network`` you want Test VMs to use. +You may need to configure ``segmentation_id`` when your network is vlan. + +Moreover, you can configure your specific flavor as below, Yardstick will setup +the stack for you. :: flavor: name: yardstick-new-flavor @@ -170,7 +222,8 @@ Moreover, you can configure your specific flavor as below, yardstick will setup disk: 2 -Besides default heat stack, yardstick also allow you to setup other two types stack. they are "Node" and "Kubernetes". :: +Besides default ``Heat`` context, Yardstick also allows you to setup two other +types of context. They are ``Node`` and ``Kubernetes``. :: context: type: Kubernetes @@ -183,48 +236,64 @@ and :: name: LF +The ``scenarios`` section is the description of testing steps, you can +orchestrate the complex testing step through scenarios. -"Scenarios" section is the description of testing step, you can orchestrate the complex testing step through orchestrate scenarios. +Each scenario will do one testing step. +In one scenario, you can configure the type of scenario (operation), ``runner`` +type and ``sla`` of the scenario. -Each scenario will do one testing step, In one scenario, you can configure the type of scenario(operation), runner type and SLA of the scenario. +For TC002, We only have one step, which is Ping from host VM to target VM. In +this step, we also have some detailed operations implemented (such as ssh to +VM, ping from VM1 to VM2. Get the latency, verify the SLA, report the result). -For TC002, We only have one step , that is Ping from host VM to target VM. In this step, we also have some detail operation implement ( such as ssh to VM, ping from VM1 to VM2. Get the latency, verify the SLA, report the result). +If you want to get this implementation details implement, you can check with +the scenario.py file. For Ping scenario, you can find it in Yardstick repo +(``yardstick/yardstick/benchmark/scenarios/networking/ping.py``). -If you want to get this detail implement , you can check with the scenario.py file. For Ping scenario, you can find it in yardstick repo ( yardstick / yardstick / benchmark / scenarios / networking / ping.py) +After you select the type of scenario (such as Ping), you will select one type +of ``runner``, there are 4 types of runner. ``Iteration`` and ``Duration`` are +the most commonly used, and the default is ``Iteration``. -after you select the type of scenario( such as Ping), you will select one type of runner, there are 4 types of runner. Usually, we use the "Iteration" and "Duration". and Default is "Iteration". -For Iteration, you can specify the iteration number and interval of iteration. :: +For ``Iteration``, you can specify the iteration number and interval of iteration. :: runner: type: Iteration iterations: 10 interval: 1 -That means yardstick will iterate the 10 times of Ping test and the interval of each iteration is one second. +That means Yardstick will repeat the Ping test 10 times and the interval of +each iteration is one second. -For Duration, you can specify the duration of this scenario and the interval of each ping test. :: +For ``Duration``, you can specify the duration of this scenario and the +interval of each ping test. :: runner: type: Duration duration: 60 interval: 10 -That means yardstick will run the ping test as loop until the total time of this scenario reach the 60s and the interval of each loop is ten seconds. - +That means Yardstick will run the ping test as loop until the total time of +this scenario reaches 60s and the interval of each loop is ten seconds. -SLA is the criterion of this scenario. that depends on the scenario. different scenario can have different SLA metric. +SLA is the criterion of this scenario. This depends on the scenario. Different +scenarios can have different SLA metric. -**How to write a new test case** -Yardstick already provide a library of testing step. that means yardstick provide lots of type scenario. +How to write a new test case +++++++++++++++++++++++++++++ -Basiclly, What you need to do is to orchestrate the scenario from the library. +Yardstick already provides a library of testing steps (i.e. different types of +scenario). -Here, We will show two cases. One is how to write a simple test case, the other is how to write a quite complex test case. +Basically, what you need to do is to orchestrate the scenario from the library. +Here, we will show two cases. One is how to write a simple test case, the other +is how to write a quite complex test case. Write a new simple test case +'''''''''''''''''''''''''''' First, you can image a basic test case description as below. @@ -314,7 +383,7 @@ First, you can image a basic test case description as below. TODO How can I contribute to Yardstick? ------------------------------------ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If you are already a contributor of any OPNFV project, you can contribute to Yardstick. If you are totally new to OPNFV, you must first create your Linux @@ -329,7 +398,7 @@ We distinguish 2 levels of contributors: Yardstick commitors are promoted by the Yardstick contributors. Gerrit & JIRA introduction -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +++++++++++++++++++++++++++ .. _Gerrit: https://www.gerritcodereview.com/ .. _`OPNFV Gerrit`: http://gerrit.opnfv.org/ @@ -338,7 +407,8 @@ Gerrit & JIRA introduction OPNFV uses Gerrit_ for web based code review and repository management for the Git Version Control System. You can access `OPNFV Gerrit`_. Please note that -you need to have Linux Foundation ID in order to use OPNFV Gerrit. You can get one from this link_. +you need to have Linux Foundation ID in order to use OPNFV Gerrit. You can get +one from this link_. OPNFV uses JIRA_ for issue management. An important principle of change management is to have two-way trace-ability between issue management @@ -350,14 +420,16 @@ If you want to contribute to Yardstick, you can pick a issue from Yardstick's JIRA dashboard or you can create you own issue and submit it to JIRA. Install Git and Git-reviews -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++++++++++++++++++++++++++++ Installing and configuring Git and Git-Review is necessary in order to submit -code to Gerrit. The `Getting to the code <https://wiki.opnfv.org/display/DEV/Developer+Getting+Started>`_ page will provide you with some help for that. +code to Gerrit. The +`Getting to the code <https://wiki.opnfv.org/display/DEV/Developer+Getting+Started>`_ +page will provide you with some help for that. Verify your patch locally before submitting -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++++++++++++++++++++++++++++++++++++++++++++ Once you finish a patch, you can submit it to Gerrit for code review. A developer sends a new patch to Gerrit will trigger patch verify job on Jenkins @@ -366,7 +438,8 @@ code coverage test. Before you submit your patch, it is recommended to run the patch verification in your local environment first. Open a terminal window and set the project's directory to the working -directory using the ``cd`` command. Assume that ``YARDSTICK_REPO_DIR`` is the path to the Yardstick project folder on your computer:: +directory using the ``cd`` command. Assume that ``YARDSTICK_REPO_DIR`` is the +path to the Yardstick project folder on your computer:: cd $YARDSTICK_REPO_DIR @@ -377,7 +450,7 @@ Verify your patch:: It is used in CI but also by the CLI. Submit the code with Git -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +++++++++++++++++++++++++ Tell Git which files you would like to take into account for the next commit. This is called 'staging' the files, by placing them into the staging area, @@ -417,7 +490,7 @@ to the commits, and eventually navigate among the latter more easily. `This document`_ happened to be very clear and useful to get started with that. Push the code to Gerrit for review -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +++++++++++++++++++++++++++++++++++ Now that the code has been comitted into your local Git repository the following step is to push it online to Gerrit for it to be reviewed. The @@ -432,27 +505,27 @@ Yardstick committers and contributors to review your codes. :width: 800px :alt: Gerrit for code review -You can find a list Yardstick people `here <https://wiki.opnfv.org/display/yardstick/People>`_, -or use the ``yardstick-reviewers`` and ``yardstick-committers`` groups in gerrit. +You can find a list Yardstick people +`here <https://wiki.opnfv.org/display/yardstick/People>`_, or use the +``yardstick-reviewers`` and ``yardstick-committers`` groups in gerrit. Modify the code under review in Gerrit -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +++++++++++++++++++++++++++++++++++++++ At the same time the code is being reviewed in Gerrit, you may need to edit it to make some changes and then send it back for review. The following steps go through the procedure. Once you have modified/edited your code files under your IDE, you will have to -stage them. The 'status' command is very helpful at this point as it provides -an overview of Git's current state:: +stage them. The ``git status`` command is very helpful at this point as it +provides an overview of Git's current state:: git status -The output of the command provides us with the files that have been modified -after the latest commit. +This command lists the files that have been modified since the last commit. You can now stage the files that have been modified as part of the Gerrit code -review edition/modification/improvement using ``git add`` command. It is now +review addition/modification/improvement using ``git add`` command. It is now time to commit the newly modified files, but the objective here is not to create a new commit, we simply want to inject the new changes into the previous commit. You can achieve that with the '--amend' option on the @@ -467,9 +540,36 @@ The final step consists in pushing the newly modified commit to Gerrit:: git review +Backporting changes to stable branches +-------------------------------------- +During the release cycle, when master and the ``stable/<release>`` branch have +diverged, it may be necessary to backport (cherry-pick) changes top the +``stable/<release>`` branch once they have merged to master. +These changes should be identified by the committers reviewing the patch. +Changes should be backported **as soon as possible** after merging of the +original code. + +..note:: + Besides the commit and review process below, the Jira tick must be updated to + add dual release versions and indicate that the change is to be backported. + +The process for backporting is as follows: + +* Committer A merges a change to master (process for normal changes). +* Committer A cherry-picks the change to ``stable/<release>`` branch (if the + bug has been identified for backporting). +* The original author should review the code and verify that it still works + (and give a ``+1``). +* Committer B reviews the change, gives a ``+2`` and merges to + ``stable/<release>``. + +A backported change needs a ``+1`` and a ``+2`` from a committer who didn’t +propose the change (i.e. minimum 3 people involved). + Plugins -========== +------- -For information about Yardstick plugins, refer to the chapter **Installing a plug-in into Yardstick** in the `user guide`_. +For information about Yardstick plugins, refer to the chapter +**Installing a plug-in into Yardstick** in the `user guide`_. diff --git a/docs/testing/developer/devguide/devguide_nsb_prox.rst b/docs/testing/developer/devguide/devguide_nsb_prox.rst index 22628413b..79990055a 100755 --- a/docs/testing/developer/devguide/devguide_nsb_prox.rst +++ b/docs/testing/developer/devguide/devguide_nsb_prox.rst @@ -244,10 +244,13 @@ Now let's examine the components of the file in detail 3. ``nodes`` - This names the Traffic Generator and the System under Test. Does not need to change. -4. ``prox_path`` - Location of the Prox executable on the traffic +4. ``interface_speed_gbps`` - This is an optional parameter. If not present + the system defaults to 10Gbps. This defines the speed of the interfaces. + +5. ``prox_path`` - Location of the Prox executable on the traffic generator (Either baremetal or Openstack Virtual Machine) -5. ``prox_config`` - This is the ``SUT Config File``. +6. ``prox_config`` - This is the ``SUT Config File``. In this case it is ``handle_l2fwd-2.cfg`` A number of additional parameters can be added. This example @@ -285,16 +288,31 @@ Now let's examine the components of the file in detail of a file called ``parameters.lua``, which contains information retrieved from either the hardware or the openstack configuration. -6. ``prox_args`` - this specifies the command line arguments to start +7. ``prox_args`` - this specifies the command line arguments to start prox. See `prox command line`_. -7. ``prox_config`` - This specifies the Traffic Generator config file. +8. ``prox_config`` - This specifies the Traffic Generator config file. + +9. ``runner`` - This is set to ``ProxDuration`` - This specifies that the + test runs for a set duration. Other runner types are available + but it is recommend to use ``ProxDuration`` + + The following parrameters are supported + + ``interval`` - (optional) - This specifies the sampling interval. + Default is 1 sec + + ``sampled`` - (optional) - This specifies if sampling information is + required. Default ``no`` + + ``duration`` - This is the length of the test in seconds. Default + is 60 seconds. -8. ``runner`` - This is set to ``Duration`` - This specified that the - test run for a set duration. Other runner types are available - but it is recommend to use ``Duration`` + ``confirmation`` - This specifies the number of confirmation retests to + be made before deciding to increase or decrease line speed. Default 0. + +10. ``context`` - This is ``context`` for a 2 port Baremetal configuration. -9. ``context`` - This is ``context`` for a 2 port Baremetal configuration. If a 4 port configuration was required then file ``prox-baremetal-4.yaml`` would be used. This is the NSB Prox baremetal configuration file. @@ -304,7 +322,8 @@ Now let's examine the components of the file in detail *Traffic Profile file* ---------------------- -This describes the details of the traffic flow. In this case ``prox_binsearch.yaml`` is used. +This describes the details of the traffic flow. In this case +``prox_binsearch.yaml`` is used. .. image:: images/PROX_Traffic_profile.png :width: 800px @@ -326,21 +345,29 @@ This describes the details of the traffic flow. In this case ``prox_binsearch.ya Custom traffic types can be created by creating a new traffic profile class. -3. ``tolerated_loss`` - This specifies the percentage of packets that can be lost/dropped before - we declare success or failure. Success is Transmitted-Packets from Traffic Generator is greater than or equal to +3. ``tolerated_loss`` - This specifies the percentage of packets that + can be lost/dropped before + we declare success or failure. Success is Transmitted-Packets from + Traffic Generator is greater than or equal to packets received by Traffic Generator plus tolerated loss. -4. ``test_precision`` - This specifies the precision of the test results. For some tests the success criteria - may never be achieved because the test precision may be greater than the successful throughput. For finer - results increase the precision by making this value smaller. +4. ``test_precision`` - This specifies the precision of the test + results. For some tests the success criteria may never be + achieved because the test precision may be greater than the + successful throughput. For finer results increase the precision + by making this value smaller. -5. ``packet_sizes`` - This specifies the range of packets size this test is run for. +5. ``packet_sizes`` - This specifies the range of packets size this + test is run for. -6. ``duration`` - This specifies the sample duration that the test uses to check for success or failure. +6. ``duration`` - This specifies the sample duration that the test + uses to check for success or failure. -7. ``lower_bound`` - This specifies the test initial lower bound sample rate. On success this value is increased. +7. ``lower_bound`` - This specifies the test initial lower bound sample rate. + On success this value is increased. -8. ``upper_bound`` - This specifies the test initial upper bound sample rate. On success this value is decreased. +8. ``upper_bound`` - This specifies the test initial upper bound sample rate. + On success this value is decreased. Other traffic profiles exist eg prox_ACL.yaml which does not compare what is received with what is transmitted. It just @@ -371,14 +398,18 @@ See this prox_vpe.yaml as example:: We will use ``tc_prox_heat_context_l2fwd-2.yaml`` as a example to show you how to understand the test description file. -.. image:: images/PROX_Test_HEAT_Script.png +.. image:: images/PROX_Test_HEAT_Script1.png :width: 800px - :alt: NSB PROX Test Description File + :alt: NSB PROX Test Description File - Part 1 + +.. image:: images/PROX_Test_HEAT_Script2.png + :width: 800px + :alt: NSB PROX Test Description File - Part 2 Now lets examine the components of the file in detail -Sections 1 to 8 are exactly the same in Baremetal and in Heat. Section -``9`` is replaced with sections A to F. Section 9 was for a baremetal +Sections 1 to 9 are exactly the same in Baremetal and in Heat. Section +``10`` is replaced with sections A to F. Section 10 was for a baremetal configuration file. This has no place in a heat configuration. A. ``image`` - yardstick-samplevnfs. This is the name of the image @@ -418,12 +449,12 @@ F. ``networks`` - is composed of a management network labeled ``mgmt`` gateway_ip: 'null' port_security_enabled: False enable_dhcp: 'false' - downlink_1: + uplink_1: cidr: '10.0.4.0/24' gateway_ip: 'null' port_security_enabled: False enable_dhcp: 'false' - downlink_2: + downlink_1: cidr: '10.0.5.0/24' gateway_ip: 'null' port_security_enabled: False @@ -1033,7 +1064,7 @@ If PROX NSB does not work on baremetal, problem is either in network configurati 1. What is received on 0 is transmitted on 1, received on 1 transmitted on 0, received on 2 transmitted on 3 and received on 3 transmitted on 2. 2. No packets are Failed. - 3. No Packets are discarded. + 3. No packets are discarded. We can also dump the packets being received or transmitted via the following commands. :: @@ -1228,7 +1259,69 @@ Where 4) ir.intel.com = local no proxy +*How to Understand the Grafana output?* +--------------------------------------- + + .. image:: images/PROX_Grafana_1.png + :width: 1000px + :alt: NSB PROX Grafana_1 + + .. image:: images/PROX_Grafana_2.png + :width: 1000px + :alt: NSB PROX Grafana_2 + + .. image:: images/PROX_Grafana_3.png + :width: 1000px + :alt: NSB PROX Grafana_3 + + .. image:: images/PROX_Grafana_4.png + :width: 1000px + :alt: NSB PROX Grafana_4 + +A. Test Parameters - Test interval, Duartion, Tolerated Loss and Test Precision + +B. Overall No of packets send and received during test + +C. Generator Stats - packets sent, received and attempted by Generator + +D. Packets Size + +E. No of packets received by SUT + +F. No of packets forwarded by SUT + +G. This is the number of packets sent by the generator per port, for each interval. + +H. This is the number of packets received by the generator per port, for each interval. + +I. This is the number of packets send and received by the generator and lost by the SUT + that meet the success criteria + +J. This is the changes the Percentage of Line Rate used over a test, The MAX and the + MIN should converge to within the interval specified as the ``test-precision``. + +K. This is the packets Size supported during test. If "N/A" appears in any field the result has not been decided. + +L. This is the calculated throughput in MPPS(Million Packets Per second) for this line rate. + +M. This is the actual No, of packets sent by the generator in MPPS + +N. This is the actual No. of packets received by the generator in MPPS + +O. This is the total No. of packets sent by SUT. + +P. This is the total No. of packets received by the SUT + +Q. This is the total No. of packets dropped. (These packets were sent by the generator but not + received back by the generator, these may be dropped by the SUT or the Generator) + +R. This is the tolerated no of packets that can be dropped. + +S. This is the test Throughput in Gbps + +T. This is the Latencey per Port +U. This is the CPU Utilization diff --git a/docs/testing/developer/devguide/images/PROX_Grafana_1.png b/docs/testing/developer/devguide/images/PROX_Grafana_1.png Binary files differnew file mode 100644 index 000000000..d272edcf3 --- /dev/null +++ b/docs/testing/developer/devguide/images/PROX_Grafana_1.png diff --git a/docs/testing/developer/devguide/images/PROX_Grafana_2.png b/docs/testing/developer/devguide/images/PROX_Grafana_2.png Binary files differnew file mode 100644 index 000000000..4f7fd4cf5 --- /dev/null +++ b/docs/testing/developer/devguide/images/PROX_Grafana_2.png diff --git a/docs/testing/developer/devguide/images/PROX_Grafana_3.png b/docs/testing/developer/devguide/images/PROX_Grafana_3.png Binary files differnew file mode 100644 index 000000000..5ae967698 --- /dev/null +++ b/docs/testing/developer/devguide/images/PROX_Grafana_3.png diff --git a/docs/testing/developer/devguide/images/PROX_Grafana_4.png b/docs/testing/developer/devguide/images/PROX_Grafana_4.png Binary files differnew file mode 100644 index 000000000..5353d1c7e --- /dev/null +++ b/docs/testing/developer/devguide/images/PROX_Grafana_4.png diff --git a/docs/testing/developer/devguide/images/PROX_Test_BM_Script.png b/docs/testing/developer/devguide/images/PROX_Test_BM_Script.png Binary files differindex 32530eb15..c09f7bb1b 100644 --- a/docs/testing/developer/devguide/images/PROX_Test_BM_Script.png +++ b/docs/testing/developer/devguide/images/PROX_Test_BM_Script.png diff --git a/docs/testing/developer/devguide/images/PROX_Test_HEAT_Script.png b/docs/testing/developer/devguide/images/PROX_Test_HEAT_Script.png Binary files differdeleted file mode 100644 index 754973b4e..000000000 --- a/docs/testing/developer/devguide/images/PROX_Test_HEAT_Script.png +++ /dev/null diff --git a/docs/testing/developer/devguide/images/PROX_Test_HEAT_Script1.png b/docs/testing/developer/devguide/images/PROX_Test_HEAT_Script1.png Binary files differnew file mode 100644 index 000000000..bd375dba1 --- /dev/null +++ b/docs/testing/developer/devguide/images/PROX_Test_HEAT_Script1.png diff --git a/docs/testing/developer/devguide/images/PROX_Test_HEAT_Script2.png b/docs/testing/developer/devguide/images/PROX_Test_HEAT_Script2.png Binary files differnew file mode 100644 index 000000000..99d9d24e6 --- /dev/null +++ b/docs/testing/developer/devguide/images/PROX_Test_HEAT_Script2.png diff --git a/docs/testing/developer/devguide/index.rst b/docs/testing/developer/devguide/index.rst index 92a18f6ee..9a76a32f1 100644 --- a/docs/testing/developer/devguide/index.rst +++ b/docs/testing/developer/devguide/index.rst @@ -14,3 +14,4 @@ Yardstick Developer Guide :numbered: devguide + devguide_nsb_prox diff --git a/docs/testing/user/userguide/14-nsb-operation.rst b/docs/testing/user/userguide/14-nsb-operation.rst index 2e741822e..a5f3a0cf6 100644 --- a/docs/testing/user/userguide/14-nsb-operation.rst +++ b/docs/testing/user/userguide/14-nsb-operation.rst @@ -84,6 +84,116 @@ In this example we have ``TRex xe0 <-> xe0 VNF xe1 <-> xe0 UDP_Replay`` downlink_0: - xe0 + +Availability zone +^^^^^^^^^^^^^^^^^ + +The configuration of the availability zone is requred in cases where location +of exact compute host/group of compute hosts needs to be specified for SampleVNF +or traffic generator in the heat test case. If this is the case, please follow +the instructions below. + +.. _`Create a host aggregate`: + +1. Create a host aggregate in the OpenStack and add the available compute hosts + into the aggregate group. + + .. note:: Change the ``<AZ_NAME>`` (availability zone name), ``<AGG_NAME>`` + (host aggregate name) and ``<HOST>`` (host name of one of the compute) in the + commands below. + + .. code-block:: bash + + # create host aggregate + openstack aggregate create --zone <AZ_NAME> --property availability_zone=<AZ_NAME> <AGG_NAME> + # show available hosts + openstack compute service list --service nova-compute + # add selected host into the host aggregate + openstack aggregate add host <AGG_NAME> <HOST> + +2. To specify the OpenStack location (the exact compute host or group of the hosts) + of SampleVNF or traffic generator in the heat test case, the ``availability_zone`` server + configuration option should be used. For example: + + .. note:: The ``<AZ_NAME>`` (availability zone name) should be changed according + to the name used during the host aggregate creation steps above. + + .. code-block:: yaml + + context: + name: yardstick + image: yardstick-samplevnfs + ... + servers: + vnf__0: + ... + availability_zone: <AZ_NAME> + ... + tg__0: + ... + availability_zone: <AZ_NAME> + ... + networks: + ... + +There are two example of SampleVNF scale out test case which use the availability zone +feature to specify the exact location of scaled VNFs and traffic generators. + +Those are: + +.. code-block:: console + + <repo>/samples/vnf_samples/nsut/prox/tc_prox_heat_context_l2fwd_multiflow-2-scale-out.yaml + <repo>/samples/vnf_samples/nsut/vfw/tc_heat_rfc2544_ipv4_1rule_1flow_64B_trex_scale_out.yaml + +.. note:: This section describes the PROX scale-out testcase, but the same + procedure is used for the vFW test case. + +1. Before running the scale-out test case, make sure the host aggregates are + configured in the OpenStack environment. To check this, run the following + command: + + .. code-block:: console + + # show configured host aggregates (example) + openstack aggregate list + +----+------+-------------------+ + | ID | Name | Availability Zone | + +----+------+-------------------+ + | 4 | agg0 | AZ_NAME_0 | + | 5 | agg1 | AZ_NAME_1 | + +----+------+-------------------+ + +2. If no host aggregates are configured, please use `steps above`__ to + configure them. + +__ `Create a host aggregate`_ + + +3. Run the SampleVNF PROX scale-out test case, specifying the availability + zone of each VNF and traffic generator as a task arguments. + + .. note:: The ``az_0`` and ``az_1`` should be changed according to the host + aggregates created in the OpenStack. + + .. code-block:: console + + yardstick -d task start\ + <repo>/samples/vnf_samples/nsut/prox/tc_prox_heat_context_l2fwd_multiflow-2-scale-out.yaml\ + --task-args='{ + "num_vnfs": 4, "availability_zone": { + "vnf_0": "az_0", "tg_0": "az_1", + "vnf_1": "az_0", "tg_1": "az_1", + "vnf_2": "az_0", "tg_2": "az_1", + "vnf_3": "az_0", "tg_3": "az_1" + } + }' + + ``num_vnfs`` specifies how many VNFs are going to be deployed in the + ``heat`` contexts. ``vnf_X`` and ``tg_X`` arguments configure the + availability zone where the VNF and traffic generator is going to be deployed. + + Collectd KPIs ------------- @@ -154,7 +264,7 @@ We set the VCPUs and memory using the ``--task-args`` options .. code-block:: console - yardstick task start --task-args='{"mem": 10480, "vcpus": 4, "ports": 2}' \ + yardstick task start --task-args='{"mem": 10480, "vcpus": 4, "vports": 2}' \ samples/vnf_samples/nsut/vfw/tc_heat_rfc2544_ipv4_1rule_1flow_64B_trex_scale-up.yaml In order to support ports scale-up, traffic and topology templates need to be used in testcase. @@ -242,7 +352,7 @@ Baremetal file: /etc/yardstick/nodes/pod.yaml Scale-Out --------------------- +--------- VNFs performance data with scale-out helps @@ -313,3 +423,39 @@ options section. options: tg_0: queues_per_port: 2 + + +Standalone configuration +------------------------ + +NSB supports certain Standalone deployment configurations. +Standalone supports provisioning a VM in a standalone visualised environment using kvm/qemu. +There two types of Standalone contexts available: OVS-DPDK and SRIOV. +OVS-DPDK uses OVS network with DPDK drivers. +SRIOV enables network traffic to bypass the software switch layer of the Hyper-V stack. + +Standalone with OVS-DPDK +^^^^^^^^^^^^^^^^^^^^^^^^ + +SampleVNF image is spawned in a VM on a baremetal server. +OVS with DPDK is installed on the baremetal server. + +.. note:: Ubuntu 17.10 requires DPDK v.17.05 and higher, DPDK v.17.05 requires OVS v.2.8.0. + +Default values for OVS-DPDK: + + * queues: 4 + * lcore_mask: "" + * pmd_cpu_mask: "0x6" + +Sample test case file +^^^^^^^^^^^^^^^^^^^^^ + + 1. Prepare SampleVNF image and copy it to ``flavor/images``. + 2. Prepare context files for TREX and SampleVNF under ``contexts/file``. + 3. Add bridge named ``br-int`` to the baremetal where SampleVNF image is deployed. + 4. Modify ``networks/phy_port`` accordingly to the baremetal setup. + 5. Run test from: + +.. literalinclude:: /submodules/yardstick/samples/vnf_samples/nsut/acl/tc_ovs_rfc2544_ipv4_1rule_1flow_64B_trex.yaml + :language: yaml diff --git a/docs/testing/user/userguide/15-list-of-tcs.rst b/docs/testing/user/userguide/15-list-of-tcs.rst index 678f0f9a9..37ce819f1 100644 --- a/docs/testing/user/userguide/15-list-of-tcs.rst +++ b/docs/testing/user/userguide/15-list-of-tcs.rst @@ -84,6 +84,8 @@ H A opnfv_yardstick_tc057.rst opnfv_yardstick_tc058.rst opnfv_yardstick_tc087.rst + opnfv_yardstick_tc092.rst + opnfv_yardstick_tc093.rst IPv6 ---- diff --git a/docs/testing/user/userguide/opnfv_yardstick_tc092.rst b/docs/testing/user/userguide/opnfv_yardstick_tc092.rst new file mode 100644 index 000000000..895074a85 --- /dev/null +++ b/docs/testing/user/userguide/opnfv_yardstick_tc092.rst @@ -0,0 +1,196 @@ +.. This work is licensed under a Creative Commons Attribution 4.0 International +.. License. +.. http://creativecommons.org/licenses/by/4.0 +.. (c) OPNFV, Ericsson and others. + +************************************* +Yardstick Test Case Description TC092 +************************************* + ++-----------------------------------------------------------------------------+ +|SDN Controller resilience in HA configuration | +| | ++--------------+--------------------------------------------------------------+ +|test case id | OPNFV_YARDSTICK_TC092: SDN controller resilience and high | +| | availability HA configuration | +| | | ++--------------+--------------------------------------------------------------+ +|test purpose | This test validates SDN controller node high availability by | +| | verifying there is no impact on the data plane connectivity | +| | when one SDN controller fails in a HA configuration, | +| | i.e. all existing configured network services DHCP, ARP, L2, | +| | L3VPN, Security Groups should continue to operate | +| | between the existing VMs while one SDN controller instance | +| | is offline and rebooting. | +| | | +| | The test also validates that network service operations such | +| | as creating a new VM in an existing or new L2 network | +| | network remain operational while one instance of the | +| | SDN controller is offline and recovers from the failure. | +| | | ++--------------+--------------------------------------------------------------+ +|test method | This test case: | +| | 1. fails one instance of a SDN controller cluster running | +| | in a HA configuration on the OpenStack controller node | +| | | +| | 2. checks if already configured L2 connectivity between | +| | existing VMs is not impacted | +| | | +| | 3. verifies that the system never loses the ability to | +| | execute virtual network operations, even when the | +| | failed SDN Controller is still recovering | +| | | ++--------------+--------------------------------------------------------------+ +|attackers | In this test case, an attacker called “kill-process” is | +| | needed. This attacker includes three parameters: | +| | 1. ``fault_type``: which is used for finding the attacker's | +| | scripts. It should be set to 'kill-process' in this test | +| | | +| | 2. ``process_name``: should be set to sdn controller | +| | process | +| | | +| | 3. ``host``: which is the name of a control node where | +| | opendaylight process is running | +| | | +| | example: | +| | - ``fault_type``: “kill-process” | +| | - ``process_name``: “opendaylight-karaf” (TBD) | +| | - ``host``: node1 | +| | | ++--------------+--------------------------------------------------------------+ +|monitors | In this test case, the following monitors are needed | +| | 1. ``ping_same_network_l2``: monitor pinging traffic | +| | between the VMs in same neutron network | +| | | +| | 2. ``ping_external_snat``: monitor ping traffic from VMs to | +| | external destinations (e.g. google.com) | +| | | +| | 3. ``SDN controller process monitor``: a monitor checking | +| | the state of a specified SDN controller process. It | +| | measures the recovery time of the given process. | +| | | ++--------------+--------------------------------------------------------------+ +|operations | In this test case, the following operations are needed: | +| | 1. "nova-create-instance-in_network": create a VM instance | +| | in one of the existing neutron network. | +| | | ++--------------+--------------------------------------------------------------+ +|metrics | In this test case, there are two metrics: | +| | 1. process_recover_time: which indicates the maximun | +| | time (seconds) from the process being killed to | +| | recovered | +| | | +| | 2. packet_drop: measure the packets that have been dropped | +| | by the monitors using pktgen. | +| | | ++--------------+--------------------------------------------------------------+ +|test tool | Developed by the project. Please see folder: | +| | "yardstick/benchmark/scenarios/availability/ha_tools" | +| | | ++--------------+--------------------------------------------------------------+ +|references | TBD | +| | | ++--------------+--------------------------------------------------------------+ +|configuration | This test case needs two configuration files: | +| | 1. test case file: opnfv_yardstick_tc092.yaml | +| | - Attackers: see above “attackers” discription | +| | - Monitors: see above “monitors” discription | +| | - waiting_time: which is the time (seconds) from the | +| | process being killed to stoping monitors the | +| | monitors | +| | - SLA: see above “metrics” discription | +| | | +| | 2. POD file: pod.yaml The POD configuration should record | +| | on pod.yaml first. the “host” item in this test case | +| | will use the node name in the pod.yaml. | +| | | ++--------------+--------------------------------------------------------------+ +|test sequence | Description and expected result | +| | | ++--------------+--------------------------------------------------------------+ +|pre-action | 1. The OpenStack cluster is set up with an SDN controller | +| | running in a three node cluster configuration. | +| | | +| | 2. One or more neutron networks are created with two or | +| | more VMs attached to each of the neutron networks. | +| | | +| | 3. The neutron networks are attached to a neutron router | +| | which is attached to an external network the towards | +| | DCGW. | +| | | +| | 4. The master node of SDN controller cluster is known. | +| | | ++--------------+--------------------------------------------------------------+ +|step 1 | Start ip connectivity monitors: | +| | 1. Check the L2 connectivity between the VMs in the same | +| | neutron network. | +| | | +| | 2. Check the external connectivity of the VMs. | +| | | +| | Each monitor runs in an independent process. | +| | | +| | Result: The monitor info will be collected. | +| | | ++--------------+--------------------------------------------------------------+ +|step 2 | Start attacker: | +| | SSH to the VIM node and kill the SDN controller process | +| | determined in step 2. | +| | | +| | Result: One SDN controller service will be shut down | +| | | ++--------------+--------------------------------------------------------------+ +|step 3 | Restart the SDN controller. | +| | | ++--------------+--------------------------------------------------------------+ +|step 4 | Create a new VM in the existing Neutron network while the | +| | SDN controller is offline or still recovering. | +| | | ++--------------+--------------------------------------------------------------+ +|step 5 | Stop IP connectivity monitors after a period of time | +| | specified by “waiting_time” | +| | | +| | Result: The monitor info will be aggregated | +| | | ++--------------+--------------------------------------------------------------+ +|step 6 | Verify the IP connectivity monitor result | +| | | +| | Result: IP connectivity monitor should not have any packet | +| | drop failures reported | +| | | ++--------------+--------------------------------------------------------------+ +|step 7 | Verify process_recover_time, which indicates the maximun | +| | time (seconds) from the process being killed to recovered, | +| | is within the SLA. This step blocks until either the | +| | process has recovered or a timeout occurred. | +| | | +| | Result: process_recover_time is within SLA limits, if not, | +| | test case failed and stopped. | +| | | ++--------------+--------------------------------------------------------------+ +|step 8 | Start IP connectivity monitors for the new VM: | +| | 1. Check the L2 connectivity from the existing VMs to the | +| | new VM in the Neutron network. | +| | | +| | 2. Check connectivity from one VM to an external host on | +| | the Internet to verify SNAT functionality. | +| | | +| | Result: The monitor info will be collected. | +| | | ++--------------+--------------------------------------------------------------+ +|step 9 | Stop IP connectivity monitors after a period of time | +| | specified by “waiting_time” | +| | | +| | Result: The monitor info will be aggregated | +| | | ++--------------+--------------------------------------------------------------+ +|step 10 | Verify the IP connectivity monitor result | +| | | +| | Result: IP connectivity monitor should not have any packet | +| | drop failures reported | +| | | ++--------------+--------------------------------------------------------------+ +|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_tc093.rst b/docs/testing/user/userguide/opnfv_yardstick_tc093.rst new file mode 100644 index 000000000..31fa5d3d3 --- /dev/null +++ b/docs/testing/user/userguide/opnfv_yardstick_tc093.rst @@ -0,0 +1,184 @@ +.. This work is licensed under a Creative Commons Attribution 4.0 International +.. License. +.. http://creativecommons.org/licenses/by/4.0 +.. (c) OPNFV, Intracom Telecom and others. +.. mardim@intracom-telecom.com + +************************************* +Yardstick Test Case Description TC093 +************************************* + ++-----------------------------------------------------------------------------+ +|SDN Vswitch resilience in non-HA or HA configuration | +| | ++--------------+--------------------------------------------------------------+ +|test case id | OPNFV_YARDSTICK_TC093: SDN Vswitch resilience in | +| | non-HA or HA configuration | ++--------------+--------------------------------------------------------------+ +|test purpose | This test validates that network data plane services are | +| | resilient in the event of Virtual Switch failure | +| | in compute nodes. Specifically, the test verifies that | +| | existing data plane connectivity is not permanently impacted | +| | i.e. all configured network services such as DHCP, ARP, L2, | +| | L3 Security Groups continue to operate between the existing | +| | VMs eventually after the Virtual Switches have finished | +| | rebooting. | +| | | +| | The test also validates that new network service operations | +| | (creating a new VM in the existing L2/L3 network or in a new | +| | network, etc.) are operational after the Virtual Switches | +| | have recovered from a failure. | +| | | ++--------------+--------------------------------------------------------------+ +|test method | This testcase first checks if the already configured | +| | DHCP/ARP/L2/L3/SNAT connectivity is proper. After | +| | it fails and restarts again the VSwitch services which are | +| | running on both OpenStack compute nodes, and then checks if | +| | already configured DHCP/ARP/L2/L3/SNAT connectivity is not | +| | permanently impacted (even if there are some packet | +| | loss events) between VMs and the system is able to execute | +| | new virtual network operations once the Vswitch services | +| | are restarted and have been fully recovered | +| | | ++--------------+--------------------------------------------------------------+ +|attackers | In this test case, two attackers called “kill-process” are | +| | needed. These attackers include three parameters: | +| | 1. fault_type: which is used for finding the attacker's | +| | scripts. It should be set to 'kill-process' in this test | +| | | +| | 2. process_name: should be set to the name of the Vswitch | +| | process | +| | | +| | 3. host: which is the name of the compute node where the | +| | Vswitch process is running | +| | | +| | e.g. -fault_type: "kill-process" | +| | -process_name: "openvswitch" | +| | -host: node1 | +| | | ++--------------+--------------------------------------------------------------+ +|monitors | This test case utilizes two monitors of type "ip-status" | +| | and one monitor of type "process" to track the following | +| | conditions: | +| | 1. "ping_same_network_l2": monitor ICMP traffic between | +| | VMs in the same Neutron network | +| | | +| | 2. "ping_external_snat": monitor ICMP traffic from VMs to | +| | an external host on the Internet to verify SNAT | +| | functionality. | +| | | +| | 3. "Vswitch process monitor": a monitor checking the | +| | state of the specified Vswitch process. It measures | +| | the recovery time of the given process. | +| | | +| | Monitors of type "ip-status" use the "ping" utility to | +| | verify reachability of a given target IP. | +| | | ++--------------+--------------------------------------------------------------+ +|operations | In this test case, the following operations are needed: | +| | 1. "nova-create-instance-in_network": create a VM instance | +| | in one of the existing Neutron network. | +| | | ++--------------+--------------------------------------------------------------+ +|metrics | In this test case, there are two metrics: | +| | 1. process_recover_time: which indicates the maximun | +| | time (seconds) from the process being killed to | +| | recovered | +| | | +| | 2. outage_time: measures the total time in which | +| | monitors were failing in their tasks (e.g. total time of | +| | Ping failure) | +| | | ++--------------+--------------------------------------------------------------+ +|test tool | Developed by the project. Please see folder: | +| | "yardstick/benchmark/scenarios/availability/ha_tools" | +| | | ++--------------+--------------------------------------------------------------+ +|references | none | +| | | ++--------------+--------------------------------------------------------------+ +|configuration | This test case needs two configuration files: | +| | 1. test case file: opnfv_yardstick_tc093.yaml | +| | - Attackers: see above “attackers” description | +| | - monitor_time: which is the time (seconds) from | +| | starting to stoping the monitors | +| | - Monitors: see above “monitors” discription | +| | - SLA: see above “metrics” description | +| | | +| | 2. POD file: pod.yaml The POD configuration should record | +| | on pod.yaml first. the “host” item in this test case | +| | will use the node name in the pod.yaml. | +| | | ++--------------+--------------------------------------------------------------+ +|test sequence | Description and expected result | +| | | ++--------------+--------------------------------------------------------------+ +|pre-action | 1. The Vswitches are set up in both compute nodes. | +| | | +| | 2. One or more Neutron networks are created with two or | +| | more VMs attached to each of the Neutron networks. | +| | | +| | 3. The Neutron networks are attached to a Neutron router | +| | which is attached to an external network towards the | +| | DCGW. | +| | | ++--------------+--------------------------------------------------------------+ +|step 1 | Start IP connectivity monitors: | +| | 1. Check the L2 connectivity between the VMs in the same | +| | Neutron network. | +| | | +| | 2. Check connectivity from one VM to an external host on | +| | the Internet to verify SNAT functionality. | +| | | +| | Result: The monitor info will be collected. | +| | | ++--------------+--------------------------------------------------------------+ +|step 2 | Start attackers: | +| | SSH connect to the VIM compute nodes and kill the Vswitch | +| | processes | +| | | +| | Result: the SDN Vswitch services will be shutdown | +| | | ++--------------+--------------------------------------------------------------+ +|step 3 | Verify the results of the IP connectivity monitors. | +| | | +| | Result: The outage_time metric reported by the monitors | +| | is not greater than the max_outage_time. | +| | | ++--------------+--------------------------------------------------------------+ +|step 4 | Restart the SDN Vswitch services. | +| | | ++--------------+--------------------------------------------------------------+ +|step 5 | Create a new VM in the existing Neutron network | +| | | ++--------------+--------------------------------------------------------------+ +|step 6 | Verify connectivity between VMs as follows: | +| | 1. Check the L2 connectivity between the previously | +| | existing VM and the newly created VM on the same | +| | Neutron network by sending ICMP messages | +| | | ++--------------+--------------------------------------------------------------+ +|step 7 | Stop IP connectivity monitors after a period of time | +| | specified by “monitor_time” | +| | | +| | Result: The monitor info will be aggregated | +| | | ++--------------+--------------------------------------------------------------+ +|step 8 | Verify the IP connectivity monitor results | +| | | +| | Result: IP connectivity monitor should not have any packet | +| | drop failures reported | +| | | ++--------------+--------------------------------------------------------------+ +|test verdict | This test fails if the SLAs are not met or if there is a | +| | test case execution problem. The SLAs are define as follows | +| | for this test: | +| | * SDN Vswitch recovery | +| | * process_recover_time <= 30 sec | +| | | +| | * no impact on data plane connectivity during SDN | +| | Vswitch failure and recovery. | +| | * packet_drop == 0 | +| | | ++--------------+--------------------------------------------------------------+ + diff --git a/gui/bower.json b/gui/bower.json index d1d934f64..311c759cb 100644 --- a/gui/bower.json +++ b/gui/bower.json @@ -22,7 +22,7 @@ "angular-sanitize": "^1.6.5" }, "resolutions": { - "angular": "~1.6.x" + "angular": "~1.7.x" }, "devDependencies": { "angular-mocks": "^1.4.0" diff --git a/nsb_setup.sh b/nsb_setup.sh index 86796c4d4..1f5344980 100755 --- a/nsb_setup.sh +++ b/nsb_setup.sh @@ -63,7 +63,7 @@ for i in "${pkg[@]}"; do fi done -pip install ansible==2.4.2 shade==1.22.2 docker-py==1.10.6 +pip install ansible==2.5.5 shade==1.22.2 docker-py==1.10.6 ANSIBLE_SCRIPTS="ansible" @@ -79,4 +79,4 @@ ansible-playbook \ -e img_property="nsb" \ ${yardstick_docker_image} \ -e YARD_IMG_ARCH='amd64' ${extra_args}\ - -i yardstick-install-inventory.ini nsb_setup.yml + -i install-inventory.ini nsb_setup.yml diff --git a/requirements.txt b/requirements.txt index 4679bc8fb..43d7120db 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,9 +11,10 @@ Babel==2.3.4 # BSD; OSI Approved BSD License Jinja2==2.9.6 # BSD; OSI Approved BSD License SQLAlchemy==1.1.12 # MIT License; OSI Approved MIT License PTable==0.9.2 # BSD (3 clause); OSI Approved BSD License -ansible==2.4.2 # GPLv3; OSI Approved GNU General Public License v3 or later (GPLv3+) +ansible==2.5.5 # GPLv3; OSI Approved GNU General Public License v3 or later (GPLv3+) backport-ipaddress==0.1; python_version <= "2.7" # OSI Approved Python Software Foundation License chainmap==1.0.2 # Python Software Foundation License; OSI Approved Python Software Foundation License +cmd2==0.8.6 # MIT License; OSI Approved MIT License django==1.8.17 # BSD; OSI Approved BSD License # NOTE(ralonsoh): django must be bumped to 1.11.8; consider the migration notes [1] # [1] https://docs.djangoproject.com/ja/1.11/ref/templates/upgrading/ @@ -28,20 +29,20 @@ futures==3.1.1;python_version=='2.7' # BSD; OSI Approved BSD License influxdb==4.1.1 # MIT License; OSI Approved MIT License IxNetwork==8.40.1124.9 # MIT License; OSI Approved MIT License jinja2schema==0.1.4 # OSI Approved BSD License -keystoneauth1==3.1.0 # OSI Approved Apache Software License -kubernetes==3.0.0a1 # OSI Approved Apache Software License +keystoneauth1==3.3.0 # OSI Approved Apache Software License +kubernetes==6.0.0 # OSI Approved Apache Software License mock==2.0.0 # OSI Approved BSD License; `BSD License`_; http://github.com/testing-cabal/mock/blob/master/LICENSE.txt msgpack-python==0.4.8 # OSI Approved Apache Software License netaddr==0.7.19 # BSD License; OSI Approved BSD License; OSI Approved MIT License netifaces==0.10.6 # MIT License; OSI Approved MIT License os-client-config==1.28.0 # OSI Approved Apache Software License -osc-lib==1.7.0 # OSI Approved Apache Software License -oslo.config==4.11.1 # OSI Approved Apache Software License +osc-lib==1.8.0 # OSI Approved Apache Software License +oslo.config==5.1.0 # OSI Approved Apache Software License oslo.i18n==3.17.0 # OSI Approved Apache Software License -oslo.messaging===5.30.2 # OSI Approved Apache Software License -oslo.privsep===1.22.1 # OSI Approved Apache Software License +oslo.messaging==5.36.0 # OSI Approved Apache Software License +oslo.privsep==1.23.0 # OSI Approved Apache Software License oslo.serialization==2.20.1 # OSI Approved Apache Software License -oslo.utils==3.28.0 # OSI Approved Apache Software License +oslo.utils==3.33.0 # OSI Approved Apache Software License paramiko==2.2.1 # LGPL; OSI Approved GNU Library or Lesser General Public License (LGPL) pbr==3.1.1 # OSI Approved Apache Software License; Apache License, Version 2.0 pika==0.10.0 # BSD; OSI Approved BSD License @@ -51,13 +52,13 @@ pycrypto==2.6.1 # Public Domain pyparsing==2.2.0 # MIT License; OSI Approved MIT License pyroute2==0.4.21 # dual license GPLv2+ and Apache v2; OSI Approved GNU General Public License v2 or later (GPLv2+); OSI Approved Apache Software License pyrsistent==0.14.1 # LICENSE.mit; OSI Approved MIT License -python-cinderclient==3.1.0 # OSI Approved Apache Software License +python-cinderclient==3.3.0 # OSI Approved Apache Software License python-glanceclient==2.8.0 # OSI Approved Apache Software License python-keystoneclient==3.13.0 # OSI Approved Apache Software License python-neutronclient==6.5.0 # OSI Approved Apache Software License python-novaclient==9.1.1 # OSI Approved Apache Software License pyzmq==16.0.2 # LGPL+BSD; OSI Approved GNU Library or Lesser General Public License (LGPL); OSI Approved BSD License -requests==2.11.1 # Apache 2.0; OSI Approved Apache Software License +requests==2.14.2 # Apache 2.0; OSI Approved Apache Software License requestsexceptions==1.3.0 # OSI Approved Apache Software License scp==0.10.2 # LGPL shade==1.22.2 # OSI Approved Apache Software License diff --git a/samples/ping_bottlenecks.yaml b/samples/ping_bottlenecks.yaml index 625d4501a..096d70e67 100644 --- a/samples/ping_bottlenecks.yaml +++ b/samples/ping_bottlenecks.yaml @@ -19,6 +19,7 @@ run_in_parallel: true {% set cpu_num = cpu_num or 1 %} {% set ram_num = ram_num or 512 %} {% set disk_num = disk_num or 7 %} +{% set dpdk_enabled = dpdk_enabled or False %} scenarios: {% for num in range(stack_num) %} @@ -43,6 +44,10 @@ contexts: vcpus: {{cpu_num}} ram: {{ram_num}} disk: {{disk_num}} + {% if dpdk_enabled %} + extra_specs: + hw:mem_page_size: "large" + {% endif %} user: ubuntu placement_groups: diff --git a/samples/vnf_samples/nsut/acl/acl_1rule.yaml b/samples/vnf_samples/nsut/acl/acl_1rule.yaml index b184a29e2..49066e924 100644 --- a/samples/vnf_samples/nsut/acl/acl_1rule.yaml +++ b/samples/vnf_samples/nsut/acl/acl_1rule.yaml @@ -11,37 +11,29 @@ # 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. - -access-list1: - acl: - access-list-entries: - - ace: - ace-oper-data: - match-counter: 0 - actions: drop,count - matches: - destination-ipv4-network: 152.16.40.20/24 - destination-port-range: - lower-port: 0 - upper-port: 65535 - source-ipv4-network: 0.0.0.0/0 - source-port-range: - lower-port: 0 - upper-port: 65535 - rule-name: rule1588 - - ace: - ace-oper-data: - match-counter: 0 - actions: drop,count - matches: - destination-ipv4-network: 0.0.0.0/0 - destination-port-range: - lower-port: 0 - upper-port: 65535 - source-ipv4-network: 152.16.100.20/24 - source-port-range: - lower-port: 0 - upper-port: 65535 - rule-name: rule1589 - acl-name: sample-ipv4-acl - acl-type: ipv4-acl +--- +access-list-entries: + - + actions: [drop,count] + matches: + destination-ipv4-network: 152.16.40.20/24 + destination-port-range: + lower-port: 0 + upper-port: 65535 + source-ipv4-network: 0.0.0.0/0 + source-port-range: + lower-port: 0 + upper-port: 65535 + rule-name: rule1588 + - + actions: [drop,count] + matches: + destination-ipv4-network: 0.0.0.0/0 + destination-port-range: + lower-port: 0 + upper-port: 65535 + source-ipv4-network: 152.16.100.20/24 + source-port-range: + lower-port: 0 + upper-port: 65535 + rule-name: rule1589 diff --git a/samples/vnf_samples/nsut/acl/acl_rules.yaml b/samples/vnf_samples/nsut/acl/acl_rules.yaml deleted file mode 100644 index b184a29e2..000000000 --- a/samples/vnf_samples/nsut/acl/acl_rules.yaml +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright (c) 2016-2017 Intel Corporation -# -# 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. - -access-list1: - acl: - access-list-entries: - - ace: - ace-oper-data: - match-counter: 0 - actions: drop,count - matches: - destination-ipv4-network: 152.16.40.20/24 - destination-port-range: - lower-port: 0 - upper-port: 65535 - source-ipv4-network: 0.0.0.0/0 - source-port-range: - lower-port: 0 - upper-port: 65535 - rule-name: rule1588 - - ace: - ace-oper-data: - match-counter: 0 - actions: drop,count - matches: - destination-ipv4-network: 0.0.0.0/0 - destination-port-range: - lower-port: 0 - upper-port: 65535 - source-ipv4-network: 152.16.100.20/24 - source-port-range: - lower-port: 0 - upper-port: 65535 - rule-name: rule1589 - acl-name: sample-ipv4-acl - acl-type: ipv4-acl diff --git a/samples/vnf_samples/nsut/acl/acl_rules.yaml.sample b/samples/vnf_samples/nsut/acl/acl_rules.yaml.sample new file mode 100644 index 000000000..4c425d44f --- /dev/null +++ b/samples/vnf_samples/nsut/acl/acl_rules.yaml.sample @@ -0,0 +1,47 @@ +# Copyright (c) 2016-2017 Intel Corporation +# +# 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. +--- +access-list-entries: + - + actions: + - count + - nat: + port: 1 + - fwd: + port: 0 + matches: + destination-ipv4-network: 152.16.40.20/24 + destination-port-range: + lower-port: 0 + upper-port: 65535 + source-ipv4-network: 0.0.0.0/0 + source-port-range: + lower-port: 0 + upper-port: 65535 + protocol-mask: 255 + protocol: 127 + priority: 1 + rule-name: rule1588 + - + actions: [drop,count] + matches: + destination-ipv4-network: 0.0.0.0/0 + destination-port-range: + lower-port: 0 + upper-port: 65535 + source-ipv4-network: 152.16.100.20/24 + source-port-range: + lower-port: 0 + upper-port: 65535 + rule-name: rule1589 diff --git a/samples/vnf_samples/nsut/acl/acl_worstcaserules.yaml b/samples/vnf_samples/nsut/acl/acl_worstcaserules.yaml index b184a29e2..6f09bb848 100644 --- a/samples/vnf_samples/nsut/acl/acl_worstcaserules.yaml +++ b/samples/vnf_samples/nsut/acl/acl_worstcaserules.yaml @@ -11,37 +11,33 @@ # 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. - -access-list1: - acl: - access-list-entries: - - ace: - ace-oper-data: - match-counter: 0 - actions: drop,count - matches: - destination-ipv4-network: 152.16.40.20/24 - destination-port-range: - lower-port: 0 - upper-port: 65535 - source-ipv4-network: 0.0.0.0/0 - source-port-range: - lower-port: 0 - upper-port: 65535 - rule-name: rule1588 - - ace: - ace-oper-data: - match-counter: 0 - actions: drop,count - matches: - destination-ipv4-network: 0.0.0.0/0 - destination-port-range: - lower-port: 0 - upper-port: 65535 - source-ipv4-network: 152.16.100.20/24 - source-port-range: - lower-port: 0 - upper-port: 65535 - rule-name: rule1589 - acl-name: sample-ipv4-acl - acl-type: ipv4-acl +--- +access-list-entries: + - + ace-oper-data: + match-counter: 0 + actions: [drop,count] + matches: + destination-ipv4-network: 152.16.40.20/24 + destination-port-range: + lower-port: 0 + upper-port: 65535 + source-ipv4-network: 0.0.0.0/0 + source-port-range: + lower-port: 0 + upper-port: 65535 + rule-name: rule1588 + - + ace-oper-data: + match-counter: 0 + actions: [drop,count] + matches: + destination-ipv4-network: 0.0.0.0/0 + destination-port-range: + lower-port: 0 + upper-port: 65535 + source-ipv4-network: 152.16.100.20/24 + source-port-range: + lower-port: 0 + upper-port: 65535 + rule-name: rule1589 diff --git a/samples/vnf_samples/nsut/acl/tc_ovs_rfc2544_ipv4_1rule_1flow_64B_trex.yaml b/samples/vnf_samples/nsut/acl/tc_ovs_rfc2544_ipv4_1rule_1flow_64B_trex.yaml index 134b15fb0..00bd186ee 100644 --- a/samples/vnf_samples/nsut/acl/tc_ovs_rfc2544_ipv4_1rule_1flow_64B_trex.yaml +++ b/samples/vnf_samples/nsut/acl/tc_ovs_rfc2544_ipv4_1rule_1flow_64B_trex.yaml @@ -42,10 +42,10 @@ scenarios: contexts: - name: yardstick type: Node - file: /etc/yardstick/nodes/standalone/pod_trex.yaml + file: etc/yardstick/nodes/standalone/pod_trex.yaml - type: StandaloneOvsDpdk name: yardstick - file: /etc/yardstick/nodes/standalone/pod_ovs.yaml + file: etc/yardstick/nodes/standalone/host_ovs.yaml vm_deploy: True ovs_properties: version: @@ -56,10 +56,12 @@ contexts: socket_0: 2048 socket_1: 2048 queues: 4 + lcore_mask: "" + pmd_cpu_mask: "0x6" vpath: "/usr/local" flavor: - images: "/var/lib/libvirt/images/ubuntu.qcow2" + images: "/var/lib/libvirt/images/yardstick-nsb-image.img" ram: 4096 extra_specs: hw:cpu_sockets: 1 diff --git a/samples/vnf_samples/nsut/cmts/cmts-tg-topology.yaml b/samples/vnf_samples/nsut/cmts/cmts-tg-topology.yaml new file mode 100644 index 000000000..81323e71c --- /dev/null +++ b/samples/vnf_samples/nsut/cmts/cmts-tg-topology.yaml @@ -0,0 +1,39 @@ +# Copyright (c) 2018 Intel Corporation +# +# 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. +--- +nsd:nsd-catalog: + nsd: + - id: cmts-tg-topology + name: cmts-tg-topology + short-name: cmts-tg-topology + description: cmts-tg-topology + constituent-vnfd: + - member-vnf-index: '1' + vnfd-id-ref: tg__0 + VNF model: ../../vnf_descriptors/tg_pktgen.yaml + - member-vnf-index: '2' + vnfd-id-ref: vnf__0 + VNF model: ../../vnf_descriptors/tg_pktgen.yaml + + vld: [] +# - id: uplink +# name: tg__0 to vnf__0 link 1 +# type: ELAN +# vnfd-connection-point-ref: +# - member-vnf-index-ref: '1' +# vnfd-connection-point-ref: sriov01 +# vnfd-id-ref: tg__0 +# - member-vnf-index-ref: '2' +# vnfd-connection-point-ref: sriov01 +# vnfd-id-ref: vnf__0 diff --git a/samples/vnf_samples/nsut/cmts/tc_k8s_pktgen_01.yaml b/samples/vnf_samples/nsut/cmts/tc_k8s_pktgen_01.yaml new file mode 100644 index 000000000..cab8bb885 --- /dev/null +++ b/samples/vnf_samples/nsut/cmts/tc_k8s_pktgen_01.yaml @@ -0,0 +1,171 @@ +# Copyright (c) 2018 Intel Corporation +# +# 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. +--- +schema: yardstick:task:0.1 +scenarios: +- type: NSPerf + traffic_profile: ../../traffic_profiles/pktgen_throughput.yaml + topology: cmts-tg-topology.yaml + nodes: + tg__0: trafficgen-k8syardstick + vnf__0: vnf-k8syardstick + options: {} + runner: + type: IterationIPC + iterations: 10 + interval: 15 + timeout: 10000 +context: + name: k8syardstick + type: Kubernetes + + servers: + vnf: + containers: + - image: si-docker.ir.intel.com/vcmts-ubuntu/vcmts-pktgen-uepi + args: ["/opt/bin/cmk isolate --conf-dir=/etc/cmk --socket-id=0 --pool=dataplane /vcmts/setup.sh anga_mac_1_ds.pcap ds"] + env: + - name: LUA_PATH + value: "/vcmts/Pktgen.lua" + - name: CMK_PROC_FS + value: "/host/proc" + resources: + requests: + pod.alpha.kubernetes.io/opaque-int-resource-cmk: "1" + ports: + - containerPort: 22022 + volumeMounts: + - name: hugepages + mountPath: /dev/hugepages + - name: sysfs + mountPath: /sys + - name: sriov + mountPath: /sriov-cni + - name: host-proc + mountPath: /host/proc + readOnly: true + - name: cmk-install-dir + mountPath: /opt/bin + - name: cmk-conf-dir + mountPath: /etc/cmk + securityContext: + allowPrivilegeEscalation: true + privileged: true + + node_ports: + - name: lua # Lower case alphanumeric characters or '-' + port: 22022 + networks: + - flannel + - sriov01 + volumes: + - name: hugepages + hostPath: + path: /dev/hugepages + - name: sysfs + hostPath: + path: /sys + - name: sriov + hostPath: + path: /var/lib/cni/sriov + - name: cmk-install-dir + hostPath: + path: /opt/bin + - name: host-proc + hostPath: + path: /proc + - name: cmk-conf-dir + hostPath: + path: /etc/cmk + + trafficgen: + containers: + - image: si-docker.ir.intel.com/vcmts-ubuntu/vcmts-pktgen-uepi + args: ["/opt/bin/cmk isolate --conf-dir=/etc/cmk --socket-id=0 --pool=dataplane /vcmts/setup.sh anga_mac_1_ds.pcap ds"] + env: + - name: LUA_PATH + value: "/vcmts/Pktgen.lua" + - name: CMK_PROC_FS + value: "/host/proc" + resources: + requests: + pod.alpha.kubernetes.io/opaque-int-resource-cmk: "1" + ports: + - containerPort: 22022 + volumeMounts: + - name: hugepages + mountPath: /dev/hugepages + - name: sysfs + mountPath: /sys + - name: sriov + mountPath: /sriov-cni + - name: host-proc + mountPath: /host/proc + readOnly: true + - name: cmk-install-dir + mountPath: /opt/bin + - name: cmk-conf-dir + mountPath: /etc/cmk + securityContext: + allowPrivilegeEscalation: true + privileged: true + + node_ports: + - name: lua # Lower case alphanumeric characters or '-' + port: 22022 + networks: + - flannel + - sriov01 + volumes: + - name: hugepages + hostPath: + path: /dev/hugepages + - name: sysfs + hostPath: + path: /sys + - name: sriov + hostPath: + path: /var/lib/cni/sriov + - name: cmk-install-dir + hostPath: + path: /opt/bin + - name: host-proc + hostPath: + path: /proc + - name: cmk-conf-dir + hostPath: + path: /etc/cmk + + networks: + flannel: + args: '[{ "delegate": { "isDefaultGateway": true }}]' + plugin: flannel + sriov01: + plugin: sriov + args: '[{"if0": "ens802f0", + "if0name": "net0", + "dpdk": { + "kernel_driver": "i40evf", + "dpdk_driver": "igb_uio", + "dpdk_tool": "/opt/nsb_bin/dpdk-devbind.py"} + }]' + sriov02: + plugin: sriov + args: '[{"if0": "ens802f0", + "if0name": "net0", + "dpdk": { + "kernel_driver": "i40evf", + "dpdk_driver": "igb_uio", + "dpdk_tool": "/opt/nsb_bin/dpdk-devbind.py"} + }]' diff --git a/samples/vnf_samples/nsut/prox/configs/gen_bng-4.cfg b/samples/vnf_samples/nsut/prox/configs/gen_bng-4.cfg index 3b9c68f3f..a70ea658b 100644 --- a/samples/vnf_samples/nsut/prox/configs/gen_bng-4.cfg +++ b/samples/vnf_samples/nsut/prox/configs/gen_bng-4.cfg @@ -56,7 +56,7 @@ mode=gen tx port=cpe0 bps=12500000 ; Ethernet + QinQ + ARP-reply -pkt inline=${sut_mac0} 70 00 00 00 00 01 ${qinq_tag_inline} 00 01 81 00 00 01 08 06 00 01 08 00 06 04 00 02 00 1e 67 3e b8 df c0 a8 01 01 00 00 00 00 00 00 c0 a8 01 01 +pkt inline=${sut_mac0} 00 00 02 00 00 02 ${qinq_tag_inline} 00 01 81 00 00 01 08 06 00 01 08 00 06 04 00 02 00 1e 67 3e b8 df c0 a8 01 01 00 00 00 00 00 00 c0 a8 01 01 ; svlan: [0..127] random=000000000XXXXXXX rand_offset=14 @@ -71,7 +71,7 @@ mode=gen tx port=cpe1 bps=12500000 ; Ethernet + QinQ + ARP-reply -pkt inline=${sut_mac2} 70 00 00 00 00 03 ${qinq_tag_inline} 00 01 81 00 00 01 08 06 00 01 08 00 06 04 00 02 00 1e 67 3e b8 df c0 a8 01 01 00 00 00 00 00 00 c0 a8 01 01 +pkt inline=${sut_mac2} 00 00 02 00 00 02 ${qinq_tag_inline} 00 01 81 00 00 01 08 06 00 01 08 00 06 04 00 02 00 1e 67 3e b8 df c0 a8 01 01 00 00 00 00 00 00 c0 a8 01 01 ; svlan: [128..255] random=000000001XXXXXXX rand_offset=14 @@ -93,8 +93,8 @@ rand_offset=14 ; cvlan: 256*[0..15]+16*[0..3]+[0..3] random=0000XXXX00XX00XX rand_offset=18 -; dst_ip: [10,11].[0..255].[0,16,32,48,64,80,96,112,128,144,160,176,192,208,224,240].[0..255] -random=0000101XXXXXXXXXXXXX0000XXXXXXXX +; dst_ip: [10,11].[odd 1..255].[16,48,80,112,144,176,208,240].[odd 1..255] +random=0000101XXXXXXXX1XXX10000XXXXXXX1 rand_offset=38 lat pos=42 @@ -105,15 +105,15 @@ mode=gen tx port=cpe1 bps=1069289928 ; Ethernet + QinQ + IP + UDP -pkt inline=${sut_mac2} 70 00 00 00 00 03 ${qinq_tag_inline} 00 01 81 00 00 01 08 00 45 00 00 1c 00 01 00 00 40 11 f7 7d c0 a8 01 01 c0 a8 01 01 00 35 00 35 00 08 7c 21 +pkt inline=${sut_mac2} 70 00 00 00 00 01 ${qinq_tag_inline} 00 01 81 00 00 01 08 00 45 00 00 1c 00 01 00 00 40 11 f7 7d c0 a8 01 01 c0 a8 01 01 00 35 00 35 00 08 7c 21 ; svlan: [128..255] random=000000001XXXXXXX rand_offset=14 ; cvlan: 256*[0..15]+16*[0..3]+[0..3] random=0000XXXX00XX00XX rand_offset=18 -; dst_ip: [10,11].[0..255].[0,16,32,48,64,80,96,112,128,144,160,176,192,208,224,240].[0..255] -random=0000101XXXXXXXXXXXXX0000XXXXXXXX +; dst_ip: [10,11].[odd 1..255].[16,48,80,112,144,176,208,240].[odd 1..255] +random=0000101XXXXXXXX1XXX10000XXXXXXX1 rand_offset=38 lat pos=42 diff --git a/samples/vnf_samples/nsut/prox/configs/gen_bng_qos-4.cfg b/samples/vnf_samples/nsut/prox/configs/gen_bng_qos-4.cfg index 3b9c68f3f..a70ea658b 100644 --- a/samples/vnf_samples/nsut/prox/configs/gen_bng_qos-4.cfg +++ b/samples/vnf_samples/nsut/prox/configs/gen_bng_qos-4.cfg @@ -56,7 +56,7 @@ mode=gen tx port=cpe0 bps=12500000 ; Ethernet + QinQ + ARP-reply -pkt inline=${sut_mac0} 70 00 00 00 00 01 ${qinq_tag_inline} 00 01 81 00 00 01 08 06 00 01 08 00 06 04 00 02 00 1e 67 3e b8 df c0 a8 01 01 00 00 00 00 00 00 c0 a8 01 01 +pkt inline=${sut_mac0} 00 00 02 00 00 02 ${qinq_tag_inline} 00 01 81 00 00 01 08 06 00 01 08 00 06 04 00 02 00 1e 67 3e b8 df c0 a8 01 01 00 00 00 00 00 00 c0 a8 01 01 ; svlan: [0..127] random=000000000XXXXXXX rand_offset=14 @@ -71,7 +71,7 @@ mode=gen tx port=cpe1 bps=12500000 ; Ethernet + QinQ + ARP-reply -pkt inline=${sut_mac2} 70 00 00 00 00 03 ${qinq_tag_inline} 00 01 81 00 00 01 08 06 00 01 08 00 06 04 00 02 00 1e 67 3e b8 df c0 a8 01 01 00 00 00 00 00 00 c0 a8 01 01 +pkt inline=${sut_mac2} 00 00 02 00 00 02 ${qinq_tag_inline} 00 01 81 00 00 01 08 06 00 01 08 00 06 04 00 02 00 1e 67 3e b8 df c0 a8 01 01 00 00 00 00 00 00 c0 a8 01 01 ; svlan: [128..255] random=000000001XXXXXXX rand_offset=14 @@ -93,8 +93,8 @@ rand_offset=14 ; cvlan: 256*[0..15]+16*[0..3]+[0..3] random=0000XXXX00XX00XX rand_offset=18 -; dst_ip: [10,11].[0..255].[0,16,32,48,64,80,96,112,128,144,160,176,192,208,224,240].[0..255] -random=0000101XXXXXXXXXXXXX0000XXXXXXXX +; dst_ip: [10,11].[odd 1..255].[16,48,80,112,144,176,208,240].[odd 1..255] +random=0000101XXXXXXXX1XXX10000XXXXXXX1 rand_offset=38 lat pos=42 @@ -105,15 +105,15 @@ mode=gen tx port=cpe1 bps=1069289928 ; Ethernet + QinQ + IP + UDP -pkt inline=${sut_mac2} 70 00 00 00 00 03 ${qinq_tag_inline} 00 01 81 00 00 01 08 00 45 00 00 1c 00 01 00 00 40 11 f7 7d c0 a8 01 01 c0 a8 01 01 00 35 00 35 00 08 7c 21 +pkt inline=${sut_mac2} 70 00 00 00 00 01 ${qinq_tag_inline} 00 01 81 00 00 01 08 00 45 00 00 1c 00 01 00 00 40 11 f7 7d c0 a8 01 01 c0 a8 01 01 00 35 00 35 00 08 7c 21 ; svlan: [128..255] random=000000001XXXXXXX rand_offset=14 ; cvlan: 256*[0..15]+16*[0..3]+[0..3] random=0000XXXX00XX00XX rand_offset=18 -; dst_ip: [10,11].[0..255].[0,16,32,48,64,80,96,112,128,144,160,176,192,208,224,240].[0..255] -random=0000101XXXXXXXXXXXXX0000XXXXXXXX +; dst_ip: [10,11].[odd 1..255].[16,48,80,112,144,176,208,240].[odd 1..255] +random=0000101XXXXXXXX1XXX10000XXXXXXX1 rand_offset=38 lat pos=42 diff --git a/samples/vnf_samples/nsut/prox/configs/gen_l2fwd-2.cfg b/samples/vnf_samples/nsut/prox/configs/gen_l2fwd-2.cfg index ba0055321..c82abdb78 100644 --- a/samples/vnf_samples/nsut/prox/configs/gen_l2fwd-2.cfg +++ b/samples/vnf_samples/nsut/prox/configs/gen_l2fwd-2.cfg @@ -49,8 +49,10 @@ mode=gen tx port=p0 bps=1250000000 ; Ethernet + IP + UDP -pkt inline=${sut_mac0} 3c fd fe 9f a3 08 08 00 45 00 00 1c 00 01 00 00 40 11 f7 7d c0 a8 01 01 c0 a8 01 01 13 88 13 88 00 08 55 7b -lat pos=38 +pkt inline=${sut_mac0} 3c fd fe 9f a3 08 08 00 45 00 00 24 00 01 00 00 40 11 f7 7d c0 a8 01 01 c0 a8 01 01 13 88 13 88 00 10 55 7b 00 01 02 03 04 05 06 07 +lat pos=42 +signature pos=46 +signature=0xcafedeca [core 2] name=gen 1 @@ -59,18 +61,25 @@ mode=gen tx port=p1 bps=1250000000 ; Ethernet + IP + UDP -pkt inline=${sut_mac1} 3c fd fe 9f a3 08 08 00 45 00 00 1c 00 01 00 00 40 11 f7 7d c0 a8 01 01 c0 a8 01 01 13 88 13 88 00 08 55 7b -lat pos=38 +pkt inline=${sut_mac1} 3c fd fe 9f a3 08 08 00 45 00 00 24 00 01 00 00 40 11 f7 7d c0 a8 01 01 c0 a8 01 01 13 88 13 88 00 10 55 7b 00 01 02 03 04 05 06 07 +lat pos=42 +signature pos=46 +signature=0xcafedeca [core 3] name=rec 0 task=0 mode=lat rx port=p0 +lat pos=42 +signature pos=46 +signature=0xcafedeca [core 4] name=rec 0 task=0 mode=lat rx port=p1 - +lat pos=42 +signature pos=46 +signature=0xcafedeca diff --git a/samples/vnf_samples/nsut/prox/configs/gen_l2fwd-4.cfg b/samples/vnf_samples/nsut/prox/configs/gen_l2fwd-4.cfg index 41c31bf82..5109c3d67 100644 --- a/samples/vnf_samples/nsut/prox/configs/gen_l2fwd-4.cfg +++ b/samples/vnf_samples/nsut/prox/configs/gen_l2fwd-4.cfg @@ -61,8 +61,10 @@ mode=gen tx port=p0 bps=1250000000 ; Ethernet + IP + UDP -pkt inline=${sut_mac0} 3c fd fe 9f a3 08 08 00 45 00 00 1c 00 01 00 00 40 11 f7 7d c0 a8 01 01 c0 a8 01 01 13 88 13 88 00 08 55 7b -lat pos=38 +pkt inline=${sut_mac0} 3c fd fe 9f a3 08 08 00 45 00 00 24 00 01 00 00 40 11 f7 7d c0 a8 01 01 c0 a8 01 01 13 88 13 88 00 10 55 7b 00 01 02 03 04 05 06 07 +lat pos=42 +signature pos=46 +signature=0xcafedeca [core 2] name=gen 1 @@ -71,8 +73,10 @@ mode=gen tx port=p1 bps=1250000000 ; Ethernet + IP + UDP -pkt inline=${sut_mac1} 3c fd fe 9f a3 08 08 00 45 00 00 1c 00 01 00 00 40 11 f7 7d c0 a8 01 01 c0 a8 01 01 13 88 13 88 00 08 55 7b -lat pos=38 +pkt inline=${sut_mac1} 3c fd fe 9f a3 08 08 00 45 00 00 24 00 01 00 00 40 11 f7 7d c0 a8 01 01 c0 a8 01 01 13 88 13 88 00 10 55 7b 00 01 02 03 04 05 06 07 +lat pos=42 +signature pos=46 +signature=0xcafedeca [core 3] name=gen 2 @@ -81,8 +85,10 @@ mode=gen tx port=p2 bps=1250000000 ; Ethernet + IP + UDP -pkt inline=${sut_mac2} 3c fd fe 9f a5 08 08 00 45 00 00 1c 00 01 00 00 40 11 f7 7d c0 a8 01 01 c0 a8 01 01 13 88 13 88 00 08 55 7b -lat pos=38 +pkt inline=${sut_mac2} 3c fd fe 9f a5 08 08 00 45 00 00 24 00 01 00 00 40 11 f7 7d c0 a8 01 01 c0 a8 01 01 13 88 13 88 00 10 55 7b 00 01 02 03 04 05 06 07 +lat pos=42 +signature pos=46 +signature=0xcafedeca [core 4] name=gen 3 @@ -91,30 +97,43 @@ mode=gen tx port=p3 bps=1250000000 ; Ethernet + IP + UDP -pkt inline=${sut_mac3} 3c fd fe 9f a5 08 08 00 45 00 00 1c 00 01 00 00 40 11 f7 7d c0 a8 01 01 c0 a8 01 01 13 88 13 88 00 08 55 7b -lat pos=38 +pkt inline=${sut_mac3} 3c fd fe 9f a5 08 08 00 45 00 00 24 00 01 00 00 40 11 f7 7d c0 a8 01 01 c0 a8 01 01 13 88 13 88 00 10 55 7b 00 01 02 03 04 05 06 07 +lat pos=42 +signature pos=46 +signature=0xcafedeca [core 5] name=rec 0 task=0 mode=lat rx port=p0 +lat pos=42 +signature pos=46 +signature=0xcafedeca [core 6] name=rec 1 task=0 mode=lat rx port=p1 +lat pos=42 +signature pos=46 +signature=0xcafedeca [core 7] name=rec 2 task=0 mode=lat rx port=p2 +lat pos=42 +signature pos=46 +signature=0xcafedeca [core 8] name=rec 3 task=0 mode=lat rx port=p3 - +lat pos=42 +signature pos=46 +signature=0xcafedeca diff --git a/samples/vnf_samples/nsut/prox/configs/gen_l3fwd-2.cfg b/samples/vnf_samples/nsut/prox/configs/gen_l3fwd-2.cfg index 61c13a0df..7cd8c52ec 100644 --- a/samples/vnf_samples/nsut/prox/configs/gen_l3fwd-2.cfg +++ b/samples/vnf_samples/nsut/prox/configs/gen_l3fwd-2.cfg @@ -47,9 +47,13 @@ task=0 mode=gen tx port=p0 bps=1250000000 -pkt inline=${sut_mac0} ${tester_mac0} 08 00 45 00 00 1c 00 01 00 00 40 11 f7 7d c0 a8 01 01 0a 00 00 00 13 88 13 88 00 08 55 7b +pkt inline=${sut_mac0} ${tester_mac0} 08 00 45 00 00 24 00 01 00 00 40 11 f7 7d c0 a8 01 01 0a 00 00 00 13 88 13 88 00 10 55 7b 00 01 02 03 04 05 06 07 random=0000101XXXXXXXXXXXXX0000XXXXXXX1 rand_offset=30 +lat pos=42 +signature pos=46 +signature=0xcafedeca + [core 2] name=p1 @@ -57,18 +61,27 @@ task=0 mode=gen tx port=p1 bps=1250000000 -pkt inline=${sut_mac1} ${tester_mac1} 08 00 45 00 00 1c 00 01 00 00 40 11 f7 7d c0 a8 01 01 0a 00 00 00 13 88 13 88 00 08 55 7b +pkt inline=${sut_mac1} ${tester_mac1} 08 00 45 00 00 24 00 01 00 00 40 11 f7 7d c0 a8 01 01 0a 00 00 00 13 88 13 88 00 10 55 7b 00 01 02 03 04 05 06 07 random=0000101XXXXXXXXXXXXX0000XXXXXXX1 rand_offset=30 +lat pos=42 +signature pos=46 +signature=0xcafedeca [core 3] name=REC_P0 task=0 mode=lat rx port=p0 +lat pos=42 +signature pos=46 +signature=0xcafedeca [core 4] name=REC_P1 task=0 mode=lat rx port=p1 +lat pos=42 +signature pos=46 +signature=0xcafedeca diff --git a/samples/vnf_samples/nsut/prox/configs/gen_l3fwd-4.cfg b/samples/vnf_samples/nsut/prox/configs/gen_l3fwd-4.cfg index 087962647..0a3795eb5 100644 --- a/samples/vnf_samples/nsut/prox/configs/gen_l3fwd-4.cfg +++ b/samples/vnf_samples/nsut/prox/configs/gen_l3fwd-4.cfg @@ -56,9 +56,12 @@ task=0 mode=gen tx port=p0 bps=1250000000 -pkt inline=${sut_mac0} ${tester_mac0} 08 00 45 00 00 1c 00 01 00 00 40 11 f7 7d c0 a8 01 01 0a 00 00 00 13 88 13 88 00 08 55 7b +pkt inline=${sut_mac0} ${tester_mac0} 08 00 45 00 00 24 00 01 00 00 40 11 f7 7d c0 a8 01 01 0a 00 00 00 13 88 13 88 00 10 55 7b 00 01 02 03 04 05 06 07 random=0000101XXXXXXXXXXXXX0000XXXXXXX1 rand_offset=30 +lat pos=42 +signature pos=46 +signature=0xcafedeca [core 2] name=p1 @@ -66,9 +69,12 @@ task=0 mode=gen tx port=p1 bps=1250000000 -pkt inline=${sut_mac1} ${tester_mac1} 08 00 45 00 00 1c 00 01 00 00 40 11 f7 7d c0 a8 01 01 0a 00 00 00 13 88 13 88 00 08 55 7b +pkt inline=${sut_mac1} ${tester_mac1} 08 00 45 00 00 24 00 01 00 00 40 11 f7 7d c0 a8 01 01 0a 00 00 00 13 88 13 88 00 10 55 7b 00 01 02 03 04 05 06 07 random=0000101XXXXXXXXXXXXX0000XXXXXXX1 rand_offset=30 +lat pos=42 +signature pos=46 +signature=0xcafedeca [core 3] name=p2 @@ -76,9 +82,12 @@ task=0 mode=gen tx port=p2 bps=1250000000 -pkt inline=${sut_mac2} ${tester_mac2} 08 00 45 00 00 1c 00 01 00 00 40 11 f7 7d c0 a8 01 01 0a 00 00 00 13 88 13 88 00 08 55 7b +pkt inline=${sut_mac2} ${tester_mac2} 08 00 45 00 00 24 00 01 00 00 40 11 f7 7d c0 a8 01 01 0a 00 00 00 13 88 13 88 00 10 55 7b 00 01 02 03 04 05 06 07 random=0000101XXXXXXXXXXXXX0000XXXXXXX1 rand_offset=30 +lat pos=42 +signature pos=46 +signature=0xcafedeca [core 4] name=p3 @@ -86,30 +95,45 @@ task=0 mode=gen tx port=p3 bps=1250000000 -pkt inline=${sut_mac3} ${tester_mac3} 08 00 45 00 00 1c 00 01 00 00 40 11 f7 7d c0 a8 01 01 0a 00 00 00 13 88 13 88 00 08 55 7b +pkt inline=${sut_mac3} ${tester_mac3} 08 00 45 00 00 24 00 01 00 00 40 11 f7 7d c0 a8 01 01 0a 00 00 00 13 88 13 88 00 10 55 7b 00 01 02 03 04 05 06 07 random=0000101XXXXXXXXXXXXX0000XXXXXXX1 rand_offset=30 +lat pos=42 +signature pos=46 +signature=0xcafedeca [core 5] name=REC_P0 task=0 mode=lat rx port=p0 +lat pos=42 +signature pos=46 +signature=0xcafedeca [core 6] name=REC_P1 task=0 mode=lat rx port=p1 +lat pos=42 +signature pos=46 +signature=0xcafedeca [core 7] name=REC_P2 task=0 mode=lat rx port=p2 +lat pos=42 +signature pos=46 +signature=0xcafedeca [core 8] name=REC_P3 task=0 mode=lat rx port=p3 +lat pos=42 +signature pos=46 +signature=0xcafedeca diff --git a/samples/vnf_samples/nsut/prox/configs/handle_bng-4.cfg b/samples/vnf_samples/nsut/prox/configs/handle_bng-4.cfg index e602fac11..7d350bd91 100644 --- a/samples/vnf_samples/nsut/prox/configs/handle_bng-4.cfg +++ b/samples/vnf_samples/nsut/prox/configs/handle_bng-4.cfg @@ -27,7 +27,7 @@ $core_lb_cpe0 =1 $core_inet0 =2 $core_lb_cpe1 =3 $core_inet1 =4 -$core_workers =13-14,15-16 +$core_workers =13-14,15-16,17-18,19-20 $core_tx_cpe0 =6 $core_tx_cpe1 =8 $core_tx_inet0 =9 diff --git a/samples/vnf_samples/nsut/prox/configs/handle_bng_qos-4.cfg b/samples/vnf_samples/nsut/prox/configs/handle_bng_qos-4.cfg index e1da4cdc0..f65b7cbf9 100644 --- a/samples/vnf_samples/nsut/prox/configs/handle_bng_qos-4.cfg +++ b/samples/vnf_samples/nsut/prox/configs/handle_bng_qos-4.cfg @@ -28,7 +28,7 @@ $core_lb_cpe0 =1 $core_inet0 =2 $core_lb_cpe1 =3 $core_inet1 =4 -$core_workers =13-14,15-16 ;sut_bng_qos_wk +$core_workers =13-14,15-16,17-18,19-20 $core_qos_cpe0 =5 $core_tx_cpe0 =6 $core_qos_cpe1 =7 diff --git a/samples/vnf_samples/nsut/prox/prox-tg-topology-4.yaml b/samples/vnf_samples/nsut/prox/prox-tg-topology-4.yaml index b4b003680..4b586b4c9 100644 --- a/samples/vnf_samples/nsut/prox/prox-tg-topology-4.yaml +++ b/samples/vnf_samples/nsut/prox/prox-tg-topology-4.yaml @@ -38,32 +38,34 @@ nsd:nsd-catalog: vnfd-id-ref: vnf__0 - id: downlink_0 - name: vnf__0 to tg__0 link 1 + name: vnf__0 to tg__0 link 2 type: ELAN vnfd-connection-point-ref: - - member-vnf-index-ref: '1' + - member-vnf-index-ref: '2' vnfd-connection-point-ref: xe1 vnfd-id-ref: vnf__0 - - member-vnf-index-ref: '2' + - member-vnf-index-ref: '1' vnfd-connection-point-ref: xe1 vnfd-id-ref: tg__0 - - id: downlink_1 - name: vnf__0 to tg__0 link 2 + + - id: uplink_1 + name: tg__0 to vnf__0 link 3 type: ELAN vnfd-connection-point-ref: - member-vnf-index-ref: '1' vnfd-connection-point-ref: xe2 - vnfd-id-ref: vnf__0 + vnfd-id-ref: tg__0 - member-vnf-index-ref: '2' vnfd-connection-point-ref: xe2 - vnfd-id-ref: tg__0 - - id: downlink_2 - name: vnf__0 to tg__0 link 3 + vnfd-id-ref: vnf__0 + + - id: downlink_1 + name: vnf__0 to tg__0 link 4 type: ELAN vnfd-connection-point-ref: - - member-vnf-index-ref: '1' + - member-vnf-index-ref: '2' vnfd-connection-point-ref: xe3 vnfd-id-ref: vnf__0 - - member-vnf-index-ref: '2' + - member-vnf-index-ref: '1' vnfd-connection-point-ref: xe3 vnfd-id-ref: tg__0 diff --git a/samples/vnf_samples/nsut/prox/prox-tg-topology-scale-out.yaml b/samples/vnf_samples/nsut/prox/prox-tg-topology-scale-out.yaml new file mode 100644 index 000000000..5f01ecb7e --- /dev/null +++ b/samples/vnf_samples/nsut/prox/prox-tg-topology-scale-out.yaml @@ -0,0 +1,53 @@ +# Copyright (c) 2018 Intel Corporation +# +# 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. +{% set num_vnfs = get(extra_args, 'num_vnfs', 1) %} +--- +nsd:nsd-catalog: + nsd: + - id: prox-tg-topology + name: prox-tg-topology + short-name: prox-tg-topology + description: prox-tg-topology + constituent-vnfd: +{% for vnf_num in range(num_vnfs|int) %} + - member-vnf-index: '{{ (vnf_num * 2) + 1 }}' + vnfd-id-ref: tg__{{ vnf_num }} + VNF model: ../../vnf_descriptors/tg_prox_tpl.yaml + - member-vnf-index: '{{ (vnf_num * 2) + 2 }}' + vnfd-id-ref: vnf__{{ vnf_num }} + VNF model: ../../vnf_descriptors/prox_vnf.yaml +{% endfor %} + vld: +{% for vnf_num in range(num_vnfs|int) %} + - id: uplink_{{ vnf_num }} + name: tg__{{ vnf_num }} to vnf__{{ vnf_num }} link {{ (vnf_num * 2) + 1 }} + type: ELAN + vnfd-connection-point-ref: + - member-vnf-index-ref: '{{ (vnf_num * 2) + 1 }}' + vnfd-connection-point-ref: xe0 + vnfd-id-ref: tg__{{ vnf_num }} + - member-vnf-index-ref: '{{ (vnf_num * 2) + 2 }}' + vnfd-connection-point-ref: xe0 + vnfd-id-ref: vnf__{{ vnf_num }} + - id: downlink_{{ vnf_num }} + name: vnf__{{ vnf_num }} to tg__{{ vnf_num }} link {{ (vnf_num * 2) + 2 }} + type: ELAN + vnfd-connection-point-ref: + - member-vnf-index-ref: '{{ (vnf_num * 2) + 1 }}' + vnfd-connection-point-ref: xe1 + vnfd-id-ref: vnf__{{ vnf_num }} + - member-vnf-index-ref: '{{ (vnf_num * 2) + 2 }}' + vnfd-connection-point-ref: xe1 + vnfd-id-ref: tg__{{ vnf_num }} +{% endfor %} diff --git a/samples/vnf_samples/nsut/prox/prox-tg-topology-scale-up.yaml b/samples/vnf_samples/nsut/prox/prox-tg-topology-scale-up.yaml new file mode 100644 index 000000000..74c48bac2 --- /dev/null +++ b/samples/vnf_samples/nsut/prox/prox-tg-topology-scale-up.yaml @@ -0,0 +1,62 @@ +# Copyright (c) 2018 Intel Corporation +# +# 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. + +{% set vports = get(extra_args, 'vports', 2) %} +nsd:nsd-catalog: + nsd: + - id: prox-tg-topology + name: prox-tg-topology + short-name: prox-tg-topology + description: prox-tg-topology + constituent-vnfd: + - member-vnf-index: '1' + vnfd-id-ref: tg__0 + VNF model: ../../vnf_descriptors/tg_prox_tpl.yaml + - member-vnf-index: '2' + vnfd-id-ref: vnf__0 + VNF model: ../../vnf_descriptors/prox_vnf.yaml + vld: + - id: uplink_0 + name: tg__0 to vnf__0 link 1 + type: ELAN + vnfd-connection-point-ref: + - member-vnf-index-ref: '1' + vnfd-connection-point-ref: xe0 + vnfd-id-ref: tg__0 + - member-vnf-index-ref: '2' + vnfd-connection-point-ref: xe0 + vnfd-id-ref: vnf__0 +{% for vport in range(vports-1|int) %} + - id: downlink_{{ vport }} + name: vnf__0 to tg__0 link {{ vport+2 }} + type: ELAN + vnfd-connection-point-ref: + - member-vnf-index-ref: '1' + vnfd-connection-point-ref: xe{{ vport+1 }} + vnfd-id-ref: vnf__0 + - member-vnf-index-ref: '2' + vnfd-connection-point-ref: xe{{ vport+1 }} + vnfd-id-ref: tg__0 +{% else %} + - id: downlink_0 + name: vnf__0 to tg__0 link 1 + type: ELAN + vnfd-connection-point-ref: + - member-vnf-index-ref: '1' + vnfd-connection-point-ref: xe0 + vnfd-id-ref: vnf__0 + - member-vnf-index-ref: '2' + vnfd-connection-point-ref: xe0 + vnfd-id-ref: tg__0 +{% endfor %}
\ No newline at end of file diff --git a/samples/vnf_samples/nsut/prox/tc_prox_baremetal_acl-scale-up.yaml b/samples/vnf_samples/nsut/prox/tc_prox_baremetal_acl-scale-up.yaml new file mode 100644 index 000000000..b6b22859d --- /dev/null +++ b/samples/vnf_samples/nsut/prox/tc_prox_baremetal_acl-scale-up.yaml @@ -0,0 +1,65 @@ +# Copyright (c) 2016-2018 Intel Corporation +# +# 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. + +{% set vports = vports or 2 %} +{% set duration = duration or 300 %} +--- +schema: "yardstick:task:0.1" + +scenarios: +- + type: NSPerf + # + # In case where we know that all the packets generated by the generator + # will bw received. Then use prox_binsearch. + # + # In the case where some or all the packets generated by the generator may + # not be received. Please use prox_acl .. (This generates packets at + # a specific rate and does not change rate. + # + traffic_profile: ../../traffic_profiles/prox_acl.yaml + extra_args: + vports: {{ vports }} + topology: prox-tg-topology-scale-up.yaml + + nodes: + tg__0: tg_0.yardstick + vnf__0: vnf_0.yardstick + + options: + vnf__0: + prox_path: /opt/nsb_bin/prox + prox_config: "configs/handle_acl-{{ vports }}.cfg" + prox_args: + "-t": "" + prox_files: + "configs/acl_rules-2.lua": "" + + tg__0: + prox_path: /opt/nsb_bin/prox + prox_config: "configs/gen_acl-{{ vports }}.cfg" + prox_args: + "-e": "" + "-t": "" + + runner: + type: Duration + # we kill after duration, independent of test duration, so set this high + duration: {{ duration }} + +context: + type: Node + name: yardstick + nfvi_type: baremetal + file: prox-baremetal-{{ vports }}.yaml diff --git a/samples/vnf_samples/nsut/prox/tc_prox_baremetal_bng-4.yaml b/samples/vnf_samples/nsut/prox/tc_prox_baremetal_bng-4.yaml index 914bace6c..1711c561a 100644 --- a/samples/vnf_samples/nsut/prox/tc_prox_baremetal_bng-4.yaml +++ b/samples/vnf_samples/nsut/prox/tc_prox_baremetal_bng-4.yaml @@ -26,6 +26,9 @@ scenarios: vnf__0: vnf_0.yardstick options: + + interface_speed_gbps: 10 + vnf__0: prox_path: /opt/nsb_bin/prox prox_config: "configs/handle_bng-4.cfg" @@ -34,6 +37,7 @@ scenarios: prox_files: "configs/gre_table.lua" : "" "configs/ipv4.lua" : "" + prox_generate_parameter: True tg__0: prox_path: /opt/nsb_bin/prox @@ -43,9 +47,12 @@ scenarios: "-t": "" runner: - type: Duration + type: ProxDuration # we kill after duration, independent of test duration, so set this high - duration: 300 + duration: 2900 + confirmation: 1 + sampled: yes + interval: 1 context: type: Node diff --git a/samples/vnf_samples/nsut/prox/tc_prox_baremetal_bng_qos-4.yaml b/samples/vnf_samples/nsut/prox/tc_prox_baremetal_bng_qos-4.yaml index 599a6e09a..a7d2d3846 100644 --- a/samples/vnf_samples/nsut/prox/tc_prox_baremetal_bng_qos-4.yaml +++ b/samples/vnf_samples/nsut/prox/tc_prox_baremetal_bng_qos-4.yaml @@ -26,6 +26,9 @@ scenarios: vnf__0: vnf_0.yardstick options: + + interface_speed_gbps: 10 + vnf__0: prox_path: /opt/nsb_bin/prox prox_config: "configs/handle_bng_qos-4.cfg" @@ -35,6 +38,7 @@ scenarios: "configs/gre_table.lua" : "" "configs/ipv4.lua" : "" "configs/dscp.lua" : "" + prox_generate_parameter: True tg__0: prox_path: /opt/nsb_bin/prox @@ -44,9 +48,12 @@ scenarios: "-t": "" runner: - type: Duration + type: ProxDuration # we kill after duration, independent of test duration, so set this high - duration: 300 + duration: 2900 + confirmation: 1 + sampled: yes + interval: 1 context: type: Node 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 ab067a836..84edcd47d 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 @@ -42,9 +42,15 @@ scenarios: "-t": "" runner: - type: Duration + type: ProxDuration + # sampling interval + interval: 1 + # sampled : yes OR sampled: no (DEFAULT yes) + sampled: yes # we kill after duration, independent of test duration, so set this high - duration: 300 + duration: 3100 + # Confirmation attempts + confirmation: 1 context: type: Node diff --git a/samples/vnf_samples/nsut/prox/tc_prox_baremetal_l2fwd-scale-up.yaml b/samples/vnf_samples/nsut/prox/tc_prox_baremetal_l2fwd-scale-up.yaml new file mode 100644 index 000000000..a346ae4bc --- /dev/null +++ b/samples/vnf_samples/nsut/prox/tc_prox_baremetal_l2fwd-scale-up.yaml @@ -0,0 +1,57 @@ +# Copyright (c) 2016-2018 Intel Corporation +# +# 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. + +{% set vports = vports or 2 %} +{% set underscore = '_' if type %} +{% set type = type or '' %} # type: {'', 'multiflow', 'pktTouch'} +{% set duration = duration or 300 %} +--- +schema: "yardstick:task:0.1" + +scenarios: +- + type: NSPerf + traffic_profile: ../../traffic_profiles/prox_binsearch.yaml + extra_args: + vports: {{ vports }} + topology: prox-tg-topology-scale-up.yaml + + nodes: + tg__0: tg_0.yardstick + vnf__0: vnf_0.yardstick + + options: + vnf__0: + prox_path: /opt/nsb_bin/prox + prox_config: "configs/handle_l2fwd{{ underscore }}{{ type }}-{{ vports }}.cfg" + prox_args: + "-t": "" + + tg__0: + prox_path: /opt/nsb_bin/prox + prox_config: "configs/gen_l2fwd{{ underscore }}{{ type }}-{{ vports }}.cfg" + prox_args: + "-e": "" + "-t": "" + + runner: + type: Duration + # we kill after duration, independent of test duration, so set this high + duration: {{ duration }} + +context: + type: Node + name: yardstick + nfvi_type: baremetal + file: prox-baremetal-{{ vports }}.yaml diff --git a/samples/vnf_samples/nsut/prox/tc_prox_baremetal_l3fwd-scale-up.yaml b/samples/vnf_samples/nsut/prox/tc_prox_baremetal_l3fwd-scale-up.yaml new file mode 100644 index 000000000..e1062d114 --- /dev/null +++ b/samples/vnf_samples/nsut/prox/tc_prox_baremetal_l3fwd-scale-up.yaml @@ -0,0 +1,57 @@ +# Copyright (c) 2016-2018 Intel Corporation +# +# 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. + +{% set vports = vports or 2 %} +{% set duration = duration or 300 %} +--- +schema: "yardstick:task:0.1" + +scenarios: +- + type: NSPerf + traffic_profile: ../../traffic_profiles/prox_binsearch.yaml + extra_args: + vports: {{ vports }} + topology: prox-tg-topology-scale-up.yaml + + nodes: + tg__0: tg_0.yardstick + vnf__0: vnf_0.yardstick + + options: + vnf__0: + prox_path: /opt/nsb_bin/prox + prox_config: "configs/handle_l3fwd-{{ vports }}.cfg" + prox_args: + "-t": "" + prox_files: + "configs/ipv4.lua" : "" + + tg__0: + prox_path: /opt/nsb_bin/prox + prox_config: "configs/gen_l3fwd-{{ vports }}.cfg" + prox_args: + "-e": "" + "-t": "" + + runner: + type: Duration + # we kill after duration, independent of test duration, so set this high + duration: {{ duration }} + +context: + type: Node + name: yardstick + nfvi_type: baremetal + file: prox-baremetal-{{ vports }}.yaml diff --git a/samples/vnf_samples/nsut/prox/tc_prox_baremetal_mpls_tagging-scale-up.yaml b/samples/vnf_samples/nsut/prox/tc_prox_baremetal_mpls_tagging-scale-up.yaml new file mode 100644 index 000000000..f45b6e9e5 --- /dev/null +++ b/samples/vnf_samples/nsut/prox/tc_prox_baremetal_mpls_tagging-scale-up.yaml @@ -0,0 +1,55 @@ +# Copyright (c) 2016-2018 Intel Corporation +# +# 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. + +{% set vports = vports or 2 %} +{% set duration = duration or 400 %} +--- +schema: "yardstick:task:0.1" + +scenarios: +- + type: NSPerf + traffic_profile: ../../traffic_profiles/prox_mpls_tag_untag.yaml + extra_args: + vports: {{ vports }} + topology: prox-tg-topology-scale-up.yaml + + nodes: + tg__0: tg_0.yardstick + vnf__0: vnf_0.yardstick + + options: + vnf__0: + prox_path: /opt/nsb_bin/prox + prox_config: "configs/handle_mpls_tag_untag-{{ vports }}.cfg" + prox_args: + "-t": "" + + tg__0: + prox_path: /opt/nsb_bin/prox + prox_config: "configs/gen_mpls_tag_untag-{{ vports }}.cfg" + prox_args: + "-e": "" + "-t": "" + + runner: + type: Duration + # we kill after duration, independent of test duration, so set this high + duration: {{ duration }} + +context: + type: Node + name: yardstick + nfvi_type: baremetal + file: prox-baremetal-{{ vports }}.yaml diff --git a/samples/vnf_samples/nsut/prox/tc_prox_baremetal_vpe-4.yaml b/samples/vnf_samples/nsut/prox/tc_prox_baremetal_vpe-4.yaml index 16dfa1b32..7b64f21bc 100644 --- a/samples/vnf_samples/nsut/prox/tc_prox_baremetal_vpe-4.yaml +++ b/samples/vnf_samples/nsut/prox/tc_prox_baremetal_vpe-4.yaml @@ -47,9 +47,12 @@ scenarios: "-t": "" runner: - type: Duration + type: ProxDuration # we kill after duration, independent of test duration, so set this high - duration: 300 + duration: 2900 + confirmation: 1 + sampled: yes + interval: 1 context: type: Node diff --git a/samples/vnf_samples/nsut/prox/tc_prox_heat_context_acl-4.yaml b/samples/vnf_samples/nsut/prox/tc_prox_heat_context_acl-4.yaml index ece618fa1..eaa940185 100644 --- a/samples/vnf_samples/nsut/prox/tc_prox_heat_context_acl-4.yaml +++ b/samples/vnf_samples/nsut/prox/tc_prox_heat_context_acl-4.yaml @@ -91,12 +91,12 @@ context: gateway_ip: 'null' port_security_enabled: False enable_dhcp: 'false' - downlink_1: + uplink_1: cidr: '10.0.4.0/24' gateway_ip: 'null' port_security_enabled: False enable_dhcp: 'false' - downlink_2: + downlink_1: cidr: '10.0.5.0/24' gateway_ip: 'null' port_security_enabled: False diff --git a/samples/vnf_samples/nsut/prox/tc_prox_heat_context_acl-scale-up.yaml b/samples/vnf_samples/nsut/prox/tc_prox_heat_context_acl-scale-up.yaml new file mode 100644 index 000000000..0a079275f --- /dev/null +++ b/samples/vnf_samples/nsut/prox/tc_prox_heat_context_acl-scale-up.yaml @@ -0,0 +1,104 @@ +# Copyright (c) 2016-2018 Intel Corporation +# +# 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. + +{% set vports = vports or 2 %} +{% set mem = mem or 20480 %} +{% set vcpus = vcpus or 10 %} +{% set disk = disk or 6 %} +{% set duration = duration or 300 %} +--- +schema: "yardstick:task:0.1" + +scenarios: +- + type: NSPerf + # + # In case where we know that all the packets generated by the generator + # will bw received. Then use prox_binsearch. + # + # In the case where some or all the packets generated by the generator may + # not be received. Please use prox_heat_acl .. (This generates packets at + # a specific rate and does not change rate. + # + traffic_profile: ../../traffic_profiles/prox_heat_acl.yaml + extra_args: + vports: {{ vports }} + topology: prox-tg-topology-scale-up.yaml + + nodes: + tg__0: tg_0.yardstick + vnf__0: vnf_0.yardstick + + options: + vnf__0: + prox_path: /opt/nsb_bin/prox + prox_config: "configs/handle_acl-{{ vports }}.cfg" + prox_args: + "-t": "" + prox_files: + "configs/acl_rules-2.lua" : "" + + tg__0: + prox_path: /opt/nsb_bin/prox + prox_config: "configs/gen_acl-{{ vports }}.cfg" + prox_args: + "-e": "" + "-t": "" + + runner: + type: Duration + # we kill after duration, independent of test duration, so set this high + duration: {{ duration }} + +context: + name: yardstick + image: yardstick-samplevnfs + user: ubuntu + flavor: + vcpus: {{ vcpus }} + ram: {{ mem }} + disk: {{ disk }} + extra_specs: + hw:cpu_sockets: 1 + hw:cpu_cores: {{ vcpus }} + hw:cpu_threads: 1 + placement_groups: + pgrp1: + policy: "availability" + + servers: + vnf_0: + floating_ip: true + placement: "pgrp1" + tg_0: + floating_ip: true + placement: "pgrp1" + + networks: + mgmt: + cidr: '10.0.1.0/24' +{% for vport in range(1,vports,2|int) %} + uplink_{{ loop.index0 }}: + cidr: '10.0.{{ vport+1 }}.0/24' + gateway_ip: 'null' + port_security_enabled: False + enable_dhcp: 'false' + + downlink_{{ loop.index0 }}: + cidr: '10.0.{{ vport+2 }}.0/24' + gateway_ip: 'null' + port_security_enabled: False + enable_dhcp: 'false' +{% endfor %} + diff --git a/samples/vnf_samples/nsut/prox/tc_prox_heat_context_bng-4.yaml b/samples/vnf_samples/nsut/prox/tc_prox_heat_context_bng-4.yaml index 67ad5e278..e4cd546bc 100644 --- a/samples/vnf_samples/nsut/prox/tc_prox_heat_context_bng-4.yaml +++ b/samples/vnf_samples/nsut/prox/tc_prox_heat_context_bng-4.yaml @@ -26,6 +26,9 @@ scenarios: vnf__0: vnf_0.yardstick options: + + interface_speed_gbps: 10 + vnf__0: prox_path: /opt/nsb_bin/prox prox_config: "configs/handle_bng-4.cfg" @@ -34,6 +37,7 @@ scenarios: prox_files: "configs/gre_table.lua" : "" "configs/ipv4.lua" : "" + prox_generate_parameter: True tg__0: prox_path: /opt/nsb_bin/prox @@ -45,14 +49,14 @@ scenarios: runner: type: Duration # we kill after duration, independent of test duration, so set this high - duration: 300 + duration: 1600 context: name: yardstick image: yardstick-samplevnfs user: ubuntu flavor: - vcpus: 18 + vcpus: 18 ram: 20480 disk: 6 extra_specs: @@ -85,12 +89,12 @@ context: gateway_ip: 'null' port_security_enabled: False enable_dhcp: 'false' - downlink_1: + uplink_1: cidr: '10.0.4.0/24' gateway_ip: 'null' port_security_enabled: False enable_dhcp: 'false' - downlink_2: + downlink_1: cidr: '10.0.5.0/24' gateway_ip: 'null' port_security_enabled: False diff --git a/samples/vnf_samples/nsut/prox/tc_prox_heat_context_bng_qos-4.yaml b/samples/vnf_samples/nsut/prox/tc_prox_heat_context_bng_qos-4.yaml index 0578bf5f7..60002f0b1 100644 --- a/samples/vnf_samples/nsut/prox/tc_prox_heat_context_bng_qos-4.yaml +++ b/samples/vnf_samples/nsut/prox/tc_prox_heat_context_bng_qos-4.yaml @@ -26,6 +26,9 @@ scenarios: vnf__0: vnf_0.yardstick options: + + interface_speed_gbps: 10 + vnf__0: prox_path: /opt/nsb_bin/prox prox_config: "configs/handle_bng_qos-4.cfg" @@ -35,6 +38,7 @@ scenarios: "configs/gre_table.lua" : "" "configs/ipv4.lua" : "" "configs/dscp.lua" : "" + prox_generate_parameter: True tg__0: prox_path: /opt/nsb_bin/prox @@ -46,7 +50,7 @@ scenarios: runner: type: Duration # we kill after duration, independent of test duration, so set this high - duration: 300 + duration: 1600 context: name: yardstick @@ -86,12 +90,12 @@ context: gateway_ip: 'null' port_security_enabled: False enable_dhcp: 'false' - downlink_1: + uplink_1: cidr: '10.0.4.0/24' gateway_ip: 'null' port_security_enabled: False enable_dhcp: 'false' - downlink_2: + downlink_1: cidr: '10.0.5.0/24' gateway_ip: 'null' port_security_enabled: False diff --git a/samples/vnf_samples/nsut/prox/tc_prox_heat_context_l2fwd-4.yaml b/samples/vnf_samples/nsut/prox/tc_prox_heat_context_l2fwd-4.yaml index a0bc7ef16..55f794325 100644 --- a/samples/vnf_samples/nsut/prox/tc_prox_heat_context_l2fwd-4.yaml +++ b/samples/vnf_samples/nsut/prox/tc_prox_heat_context_l2fwd-4.yaml @@ -81,12 +81,12 @@ context: gateway_ip: 'null' port_security_enabled: False enable_dhcp: 'false' - downlink_1: + uplink_1: cidr: '10.0.4.0/24' gateway_ip: 'null' port_security_enabled: False enable_dhcp: 'false' - downlink_2: + downlink_1: cidr: '10.0.5.0/24' gateway_ip: 'null' port_security_enabled: False diff --git a/samples/vnf_samples/nsut/prox/tc_prox_heat_context_l2fwd-l3fwd-scale-up.yaml b/samples/vnf_samples/nsut/prox/tc_prox_heat_context_l2fwd-l3fwd-scale-up.yaml new file mode 100644 index 000000000..af2ab15ce --- /dev/null +++ b/samples/vnf_samples/nsut/prox/tc_prox_heat_context_l2fwd-l3fwd-scale-up.yaml @@ -0,0 +1,128 @@ +# Copyright (c) 2016-2018 Intel Corporation +# +# 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. + +{% set vports = vports or 2 %} +{% set mem = mem or 20480 %} +{% set vcpus = vcpus or 10 %} +{% set disk = disk or 6 %} +{% set timeout = timeout or 300 %} +--- +schema: "yardstick:task:0.1" + +scenarios: +- + type: NSPerf + traffic_profile: ../../traffic_profiles/prox_binsearch.yaml + extra_args: + vports: {{ vports }} + topology: prox-tg-topology-scale-up.yaml + + nodes: + tg__0: tg_0.yardstick + vnf__0: vnf_0.yardstick + + options: + vnf__0: + prox_path: /opt/nsb_bin/prox + prox_config: "configs/handle_l2fwd-{{ vports }}.cfg" + prox_args: + "-t": "" + + tg__0: + prox_path: /opt/nsb_bin/prox + prox_config: "configs/gen_l2fwd-{{ vports }}.cfg" + prox_args: + "-e": "" + "-t": "" + + runner: + type: Search + # we kill after duration, independent of test duration, so set this high + interval: 5 + timeout: {{ timeout }} + +- + type: NSPerf + traffic_profile: ../../traffic_profiles/prox_binsearch.yaml + extra_args: + vports: {{ vports }} + topology: prox-tg-topology-scale-up.yaml + + nodes: + tg__0: tg_0.yardstick + vnf__0: vnf_0.yardstick + + options: + vnf__0: + prox_path: /opt/nsb_bin/prox + prox_config: "configs/handle_l3fwd-{{ vports }}.cfg" + prox_args: + "-t": "" + prox_files: + "configs/ipv4.lua" : "" + + tg__0: + prox_path: /opt/nsb_bin/prox + prox_config: "configs/gen_l3fwd-{{ vports }}.cfg" + prox_args: + "-e": "" + "-t": "" + + runner: + type: Search + # we kill after duration, independent of test duration, so set this high + interval: 5 + timeout: {{ timeout }} + +context: + name: yardstick + image: yardstick-samplevnfs + user: ubuntu + flavor: + vcpus: {{ vcpus }} + ram: {{ mem }} + disk: {{ disk }} + extra_specs: + hw:cpu_sockets: 1 + hw:cpu_cores: {{ vcpus }} + hw:cpu_threads: 1 + + placement_groups: + pgrp1: + policy: "availability" + + servers: + vnf_0: + floating_ip: true + placement: "pgrp1" + tg_0: + floating_ip: true + placement: "pgrp1" + + networks: + mgmt: + cidr: '10.0.1.0/24' +{% for vport in range(1,vports,2|int) %} + uplink_{{ loop.index0 }}: + cidr: '10.0.{{ vport+1 }}.0/24' + gateway_ip: 'null' + port_security_enabled: False + enable_dhcp: 'false' + + downlink_{{ loop.index0 }}: + cidr: '10.0.{{ vport+2 }}.0/24' + gateway_ip: 'null' + port_security_enabled: False + enable_dhcp: 'false' +{% endfor %} diff --git a/samples/vnf_samples/nsut/prox/tc_prox_heat_context_l2fwd-scale-up.yaml b/samples/vnf_samples/nsut/prox/tc_prox_heat_context_l2fwd-scale-up.yaml new file mode 100644 index 000000000..4463729fb --- /dev/null +++ b/samples/vnf_samples/nsut/prox/tc_prox_heat_context_l2fwd-scale-up.yaml @@ -0,0 +1,94 @@ +# Copyright (c) 2016-2018 Intel Corporation +# +# 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. + +{% set vports = vports or 2 %} +{% set underscore = '_' if type %} +{% set type = type or '' %} # type: {'', 'multiflow', 'pktTouch'} +{% set mem = mem or 20480 %} +{% set vcpus = vcpus or 10 %} +{% set disk = disk or 6 %} +{% set duration = duration or 300 %} +--- +schema: "yardstick:task:0.1" + +scenarios: +- + type: NSPerf + traffic_profile: ../../traffic_profiles/prox_binsearch.yaml + extra_args: + vports: {{ vports }} + topology: prox-tg-topology-scale-up.yaml + + nodes: + tg__0: tg_0.yardstick + vnf__0: vnf_0.yardstick + + options: + vnf__0: + prox_path: /opt/nsb_bin/prox + prox_config: "configs/handle_l2fwd{{ underscore }}{{ type }}-{{ vports }}.cfg" + prox_args: + "-t": "" + + tg__0: + prox_path: /opt/nsb_bin/prox + prox_config: "configs/gen_l2fwd{{ underscore }}{{ type }}-{{ vports }}.cfg" + prox_args: + "-e": "" + "-t": "" + + runner: + type: Duration + # we kill after duration, independent of test duration, so set this high + duration: {{ duration }} + +context: + name: yardstick + image: yardstick-samplevnfs + user: ubuntu + flavor: + vcpus: {{ vcpus }} + ram: {{ mem }} + disk: {{ disk }} + extra_specs: + hw:cpu_sockets: 1 + hw:cpu_cores: {{ vcpus }} + hw:cpu_threads: 1 + placement_groups: + pgrp1: + policy: "availability" + + servers: + vnf_0: + floating_ip: true + placement: "pgrp1" + tg_0: + floating_ip: true + placement: "pgrp1" + + networks: + mgmt: + cidr: '10.0.1.0/24' + uplink_0: + cidr: '10.0.2.0/24' + gateway_ip: 'null' + port_security_enabled: False + enable_dhcp: 'false' +{% for vport in range(vports-1|int) %} + downlink_{{ vport }}: + cidr: '10.0.{{ vport+3 }}.0/24' + gateway_ip: 'null' + port_security_enabled: False + enable_dhcp: 'false' +{% endfor %} diff --git a/samples/vnf_samples/nsut/prox/tc_prox_heat_context_l2fwd_multiflow-2-scale-out.yaml b/samples/vnf_samples/nsut/prox/tc_prox_heat_context_l2fwd_multiflow-2-scale-out.yaml new file mode 100644 index 000000000..88581d2da --- /dev/null +++ b/samples/vnf_samples/nsut/prox/tc_prox_heat_context_l2fwd_multiflow-2-scale-out.yaml @@ -0,0 +1,113 @@ +# Copyright (c) 2018 Intel Corporation +# +# 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. +{% set num_vnfs = num_vnfs or 1 %} +{% set availability_zone = availability_zone or {} %} +--- +schema: "yardstick:task:0.1" +scenarios: +- + type: NSPerf + traffic_profile: ../../traffic_profiles/prox_binsearch.yaml + topology: prox-tg-topology-scale-out.yaml + extra_args: + num_vnfs: {{ num_vnfs }} + + nodes: +{% for vnf_num in range(num_vnfs|int) %} + tg__{{ vnf_num }}: tg_{{ vnf_num }}.yardstick + vnf__{{ vnf_num }}: vnf_{{ vnf_num }}.yardstick +{% endfor %} + + options: +{% for vnf_num in range(num_vnfs|int) %} + vnf__{{ vnf_num }}: + prox_path: /opt/nsb_bin/prox + prox_config: "configs/handle_l2fwd_multiflow-2.cfg" + prox_args: + "-t": "" + + tg__{{ vnf_num }}: + prox_path: /opt/nsb_bin/prox + prox_config: "configs/gen_l2fwd_multiflow-2.cfg" + prox_args: + "-e": "" + "-t": "" +{% endfor %} + + runner: + type: Duration + # we kill after duration, independent of test duration, so set this high + duration: 300 + +context: + name: yardstick + image: yardstick-samplevnfs + user: ubuntu + flavor: + vcpus: 8 + ram: 20480 + disk: 10 + extra_specs: + hw:cpu_sockets: 1 + hw:cpu_cores: 8 + hw:cpu_threads: 1 + placement_groups: + pgrp1: + policy: "availability" + + servers: +{% for vnf_num in range(num_vnfs|int) %} + vnf_{{ vnf_num }}: + floating_ip: true + placement: "pgrp1" + {% if 'vnf_%s'|format(vnf_num) in availability_zone %} + availability_zone: "{{ availability_zone['vnf_%s'|format(vnf_num)] }}" + {% endif %} + network_ports: + mgmt: + - mgmt + uplink_{{ vnf_num }}: + - xe0 + downlink_{{ vnf_num }}: + - xe1 + tg_{{ vnf_num }}: + floating_ip: true + placement: "pgrp1" + {% if 'tg_%s'|format(vnf_num) in availability_zone %} + availability_zone: "{{ availability_zone['tg_%s'|format(vnf_num)] }}" + {% endif %} + network_ports: + mgmt: + - mgmt + uplink_{{ vnf_num }}: + - xe0 + downlink_{{ vnf_num }}: + - xe1 +{% endfor %} + + networks: + mgmt: + cidr: '10.0.1.0/24' +{% for vnf_num in range(num_vnfs|int) %} + uplink_{{ vnf_num }}: + cidr: '10.0.{{ (vnf_num * 2) + 2 }}.0/24' + gateway_ip: 'null' + port_security_enabled: False + enable_dhcp: 'false' + downlink_{{ vnf_num }}: + cidr: '10.0.{{ (vnf_num * 2) + 3 }}.0/24' + gateway_ip: 'null' + port_security_enabled: False + enable_dhcp: 'false' +{% endfor %} diff --git a/samples/vnf_samples/nsut/prox/tc_prox_heat_context_l2fwd_multiflow-4.yaml b/samples/vnf_samples/nsut/prox/tc_prox_heat_context_l2fwd_multiflow-4.yaml index 321b17373..4a20fad84 100644 --- a/samples/vnf_samples/nsut/prox/tc_prox_heat_context_l2fwd_multiflow-4.yaml +++ b/samples/vnf_samples/nsut/prox/tc_prox_heat_context_l2fwd_multiflow-4.yaml @@ -81,12 +81,12 @@ context: gateway_ip: 'null' port_security_enabled: False enable_dhcp: 'false' - downlink_1: + uplink_1: cidr: '10.0.4.0/24' gateway_ip: 'null' port_security_enabled: False enable_dhcp: 'false' - downlink_2: + downlink_1: cidr: '10.0.5.0/24' gateway_ip: 'null' port_security_enabled: False diff --git a/samples/vnf_samples/nsut/prox/tc_prox_heat_context_l2fwd_pktTouch-4.yaml b/samples/vnf_samples/nsut/prox/tc_prox_heat_context_l2fwd_pktTouch-4.yaml index 05723cab3..a3ac21a59 100644 --- a/samples/vnf_samples/nsut/prox/tc_prox_heat_context_l2fwd_pktTouch-4.yaml +++ b/samples/vnf_samples/nsut/prox/tc_prox_heat_context_l2fwd_pktTouch-4.yaml @@ -81,12 +81,12 @@ context: gateway_ip: 'null' port_security_enabled: False enable_dhcp: 'false' - downlink_1: + uplink_1: cidr: '10.0.4.0/24' gateway_ip: 'null' port_security_enabled: False enable_dhcp: 'false' - downlink_2: + downlink_1: cidr: '10.0.5.0/24' gateway_ip: 'null' port_security_enabled: False diff --git a/samples/vnf_samples/nsut/prox/tc_prox_heat_context_l3fwd-4.yaml b/samples/vnf_samples/nsut/prox/tc_prox_heat_context_l3fwd-4.yaml index db18949fc..7d7d2b02a 100644 --- a/samples/vnf_samples/nsut/prox/tc_prox_heat_context_l3fwd-4.yaml +++ b/samples/vnf_samples/nsut/prox/tc_prox_heat_context_l3fwd-4.yaml @@ -85,12 +85,12 @@ context: gateway_ip: 'null' port_security_enabled: False enable_dhcp: 'false' - downlink_1: + uplink_1: cidr: '10.0.4.0/24' gateway_ip: 'null' port_security_enabled: False enable_dhcp: 'false' - downlink_2: + downlink_1: cidr: '10.0.5.0/24' gateway_ip: 'null' port_security_enabled: False diff --git a/samples/vnf_samples/nsut/prox/tc_prox_heat_context_l3fwd-scale-up.yaml b/samples/vnf_samples/nsut/prox/tc_prox_heat_context_l3fwd-scale-up.yaml new file mode 100644 index 000000000..52fe8fcf4 --- /dev/null +++ b/samples/vnf_samples/nsut/prox/tc_prox_heat_context_l3fwd-scale-up.yaml @@ -0,0 +1,97 @@ +# Copyright (c) 2016-2018 Intel Corporation +# +# 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. + +{% set vports = vports or 2 %} +{% set mem = mem or 20480 %} +{% set vcpus = vcpus or 10 %} +{% set disk = disk or 6 %} +{% set duration = duration or 300 %} +--- +schema: "yardstick:task:0.1" + +scenarios: +- + type: NSPerf + traffic_profile: ../../traffic_profiles/prox_binsearch.yaml + extra_args: + vports: {{ vports }} + topology: prox-tg-topology-scale-up.yaml + + nodes: + tg__0: tg_0.yardstick + vnf__0: vnf_0.yardstick + + options: + vnf__0: + prox_path: /opt/nsb_bin/prox + prox_config: "configs/handle_l3fwd-{{ vports }}.cfg" + prox_args: + "-t": "" + prox_files: + "configs/ipv4.lua" : "" + + tg__0: + prox_path: /opt/nsb_bin/prox + prox_config: "configs/gen_l3fwd-{{ vports }}.cfg" + prox_args: + "-e": "" + "-t": "" + + runner: + type: Duration + # we kill after duration, independent of test duration, so set this high + duration: {{ duration }} + +context: + name: yardstick + image: yardstick-samplevnfs + user: ubuntu + flavor: + vcpus: {{ vcpus }} + ram: {{ mem }} + disk: {{ disk }} + extra_specs: + hw:cpu_sockets: 1 + hw:cpu_cores: {{ vcpus }} + hw:cpu_threads: 1 + + placement_groups: + pgrp1: + policy: "availability" + + servers: + vnf_0: + floating_ip: true + placement: "pgrp1" + tg_0: + floating_ip: true + placement: "pgrp1" + + networks: + mgmt: + cidr: '10.0.1.0/24' +{% for vport in range(1,vports,2|int) %} + uplink_{{ loop.index0 }}: + cidr: '10.0.{{ vport+1 }}.0/24' + gateway_ip: 'null' + port_security_enabled: False + enable_dhcp: 'false' + + downlink_{{ loop.index0 }}: + cidr: '10.0.{{ vport+2 }}.0/24' + gateway_ip: 'null' + port_security_enabled: False + enable_dhcp: 'false' +{% endfor %} + diff --git a/samples/vnf_samples/nsut/prox/tc_prox_heat_context_lb-4.yaml b/samples/vnf_samples/nsut/prox/tc_prox_heat_context_lb-4.yaml index 736f1c4c1..c34b4d99a 100644 --- a/samples/vnf_samples/nsut/prox/tc_prox_heat_context_lb-4.yaml +++ b/samples/vnf_samples/nsut/prox/tc_prox_heat_context_lb-4.yaml @@ -84,12 +84,12 @@ context: gateway_ip: 'null' port_security_enabled: False enable_dhcp: 'false' - downlink_1: + uplink_1: cidr: '10.0.4.0/24' gateway_ip: 'null' port_security_enabled: False enable_dhcp: 'false' - downlink_2: + downlink_1: cidr: '10.0.5.0/24' gateway_ip: 'null' port_security_enabled: False diff --git a/samples/vnf_samples/nsut/prox/tc_prox_heat_context_mpls_tagging-4.yaml b/samples/vnf_samples/nsut/prox/tc_prox_heat_context_mpls_tagging-4.yaml index d9cc4bc57..24f7ce4b7 100644 --- a/samples/vnf_samples/nsut/prox/tc_prox_heat_context_mpls_tagging-4.yaml +++ b/samples/vnf_samples/nsut/prox/tc_prox_heat_context_mpls_tagging-4.yaml @@ -82,12 +82,12 @@ context: gateway_ip: 'null' port_security_enabled: False enable_dhcp: 'false' - downlink_1: + uplink_1: cidr: '10.0.4.0/24' gateway_ip: 'null' port_security_enabled: False enable_dhcp: 'false' - downlink_2: + downlink_1: cidr: '10.0.5.0/24' gateway_ip: 'null' port_security_enabled: False diff --git a/samples/vnf_samples/nsut/prox/tc_prox_heat_context_mpls_tagging-scale-up.yaml b/samples/vnf_samples/nsut/prox/tc_prox_heat_context_mpls_tagging-scale-up.yaml new file mode 100644 index 000000000..6370360e4 --- /dev/null +++ b/samples/vnf_samples/nsut/prox/tc_prox_heat_context_mpls_tagging-scale-up.yaml @@ -0,0 +1,94 @@ +# Copyright (c) 2016-2018 Intel Corporation +# +# 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. + +{% set vports = vports or 2 %} +{% set mem = mem or 20480 %} +{% set vcpus = vcpus or 10 %} +{% set disk = disk or 6 %} +{% set duration = duration or 300 %} +--- +schema: "yardstick:task:0.1" + +scenarios: +- + type: NSPerf + traffic_profile: ../../traffic_profiles/prox_mpls_tag_untag.yaml + extra_args: + vports: {{ vports }} + topology: prox-tg-topology-scale-up.yaml + + nodes: + tg__0: tg_0.yardstick + vnf__0: vnf_0.yardstick + + options: + vnf__0: + prox_path: /opt/nsb_bin/prox + prox_config: "configs/handle_mpls_tag_untag-{{ vports }}.cfg" + prox_args: + "-t": "" + + tg__0: + prox_path: /opt/nsb_bin/prox + prox_config: "configs/gen_mpls_tag_untag-{{ vports }}.cfg" + prox_args: + "-e": "" + "-t": "" + + runner: + type: Duration + # we kill after duration, independent of test duration, so set this high + duration: {{ duration }} + +context: + name: yardstick + image: yardstick-samplevnfs + user: ubuntu + flavor: + vcpus: {{ vcpus }} + ram: {{ mem }} + disk: {{ disk }} + extra_specs: + hw:cpu_sockets: 1 + hw:cpu_cores: {{ vcpus }} + hw:cpu_threads: 1 + + placement_groups: + pgrp1: + policy: "availability" + + servers: + vnf_0: + floating_ip: true + placement: "pgrp1" + tg_0: + floating_ip: true + placement: "pgrp1" + + networks: + mgmt: + cidr: '10.0.1.0/24' +{% for vport in range(1,vports,2|int) %} + uplink_{{ loop.index0 }}: + cidr: '10.0.{{ vport+1 }}.0/24' + gateway_ip: 'null' + port_security_enabled: False + enable_dhcp: 'false' + + downlink_{{ loop.index0 }}: + cidr: '10.0.{{ vport+2 }}.0/24' + gateway_ip: 'null' + port_security_enabled: False + enable_dhcp: 'false' +{% endfor %} diff --git a/samples/vnf_samples/nsut/prox/tc_prox_heat_context_vpe-4.yaml b/samples/vnf_samples/nsut/prox/tc_prox_heat_context_vpe-4.yaml index 4e2e70bb4..29277ca94 100644 --- a/samples/vnf_samples/nsut/prox/tc_prox_heat_context_vpe-4.yaml +++ b/samples/vnf_samples/nsut/prox/tc_prox_heat_context_vpe-4.yaml @@ -49,7 +49,7 @@ scenarios: runner: type: Duration # we kill after duration, independent of test duration, so set this high - duration: 300 + duration: 1600 context: name: yardstick @@ -89,12 +89,12 @@ context: gateway_ip: 'null' port_security_enabled: False enable_dhcp: 'false' - downlink_1: + uplink_1: cidr: '10.0.4.0/24' gateway_ip: 'null' port_security_enabled: False enable_dhcp: 'false' - downlink_2: + downlink_1: cidr: '10.0.5.0/24' gateway_ip: 'null' port_security_enabled: False diff --git a/samples/vnf_samples/nsut/vfw/acl_1rule.yaml b/samples/vnf_samples/nsut/vfw/acl_1rule.yaml index 6753645ba..f7569b32c 100644 --- a/samples/vnf_samples/nsut/vfw/acl_1rule.yaml +++ b/samples/vnf_samples/nsut/vfw/acl_1rule.yaml @@ -11,37 +11,29 @@ # 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. - -access-list1: - acl: - access-list-entries: - - ace: - ace-oper-data: - match-counter: 0 - actions: drop,count - matches: - destination-ipv4-network: 152.16.0.0/24 - destination-port-range: - lower-port: 0 - upper-port: 65535 - source-ipv4-network: 0.0.0.0/0 - source-port-range: - lower-port: 0 - upper-port: 65535 - rule-name: rule1588 - - ace: - ace-oper-data: - match-counter: 0 - actions: drop,count - matches: - destination-ipv4-network: 0.0.0.0/0 - destination-port-range: - lower-port: 0 - upper-port: 65535 - source-ipv4-network: 152.16.0.0/24 - source-port-range: - lower-port: 0 - upper-port: 65535 - rule-name: rule1589 - acl-name: sample-ipv4-acl - acl-type: ipv4-acl +--- +access-list-entries: + - + actions: [drop,count] + matches: + destination-ipv4-network: 152.16.0.0/24 + destination-port-range: + lower-port: 0 + upper-port: 65535 + source-ipv4-network: 0.0.0.0/0 + source-port-range: + lower-port: 0 + upper-port: 65535 + rule-name: rule1588 + - + actions: [drop,count] + matches: + destination-ipv4-network: 0.0.0.0/0 + destination-port-range: + lower-port: 0 + upper-port: 65535 + source-ipv4-network: 152.16.0.0/24 + source-port-range: + lower-port: 0 + upper-port: 65535 + rule-name: rule1589 diff --git a/samples/vnf_samples/nsut/vfw/tc_heat_rfc2544_ipv4_1rule_1flow_64B_trex_iterationipc.yaml b/samples/vnf_samples/nsut/vfw/tc_heat_rfc2544_ipv4_1rule_1flow_64B_trex_iterationipc.yaml new file mode 100644 index 000000000..184ed6881 --- /dev/null +++ b/samples/vnf_samples/nsut/vfw/tc_heat_rfc2544_ipv4_1rule_1flow_64B_trex_iterationipc.yaml @@ -0,0 +1,96 @@ +# Copyright (c) 2016-2017 Intel Corporation +# +# 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. + +--- +{% set provider = provider or none %} +{% set physical_networks = physical_networks or ['physnet1', 'physnet2'] %} +{% set segmentation_id = segmentation_id or none %} + +schema: yardstick:task:0.1 +scenarios: +- type: NSPerf + traffic_profile: ../../traffic_profiles/ipv4_throughput.yaml + topology: vfw-tg-topology.yaml + nodes: + tg__0: trafficgen_1.yardstick + vnf__0: vnf.yardstick + options: + hugepages_gb: 8 + framesize: + uplink: {64B: 100} + downlink: {64B: 100} + flow: + src_ip: [{'tg__0': 'xe0'}] + dst_ip: [{'tg__0': 'xe1'}] + count: 1 + traffic_type: 4 + rfc2544: + allowed_drop_rate: 0.0001 - 0.0001 + vnf__0: + rules: acl_1rule.yaml + vnf_config: {lb_config: 'SW', lb_count: 1, worker_config: '1C/1T', worker_threads: 1} + runner: + type: IterationIPC + iterations: 10 + timeout: 60 +context: + # put node context first, so we don't HEAT deploy if node has errors + name: yardstick + image: yardstick-samplevnfs + flavor: + vcpus: 10 + ram: 12288 + disk: 6 + extra_specs: + hw:cpu_sockets: 1 + hw:cpu_cores: 10 + hw:cpu_threads: 1 + user: ubuntu + placement_groups: + pgrp1: + policy: "availability" + servers: + vnf: + floating_ip: true + placement: "pgrp1" + trafficgen_1: + floating_ip: true + placement: "pgrp1" + networks: + mgmt: + cidr: '10.0.1.0/24' + xe0: + cidr: '10.0.2.0/24' + gateway_ip: 'null' + {% if provider %} + provider: {{ provider }} + physical_network: {{ physical_networks[0] }} + {% if segmentation_id %} + segmentation_id: {{ segmentation_id }} + {% endif %} + {% endif %} + port_security_enabled: False + enable_dhcp: 'false' + xe1: + cidr: '10.0.3.0/24' + gateway_ip: 'null' + {% if provider %} + provider: {{ provider }} + physical_network: {{ physical_networks[1] }} + {% if segmentation_id %} + segmentation_id: {{ segmentation_id }} + {% endif %} + {% endif %} + port_security_enabled: False + enable_dhcp: 'false' diff --git a/samples/vnf_samples/nsut/vfw/tc_heat_rfc2544_ipv4_1rule_1flow_64B_trex_scale_out.yaml b/samples/vnf_samples/nsut/vfw/tc_heat_rfc2544_ipv4_1rule_1flow_64B_trex_scale_out.yaml new file mode 100644 index 000000000..f1408931f --- /dev/null +++ b/samples/vnf_samples/nsut/vfw/tc_heat_rfc2544_ipv4_1rule_1flow_64B_trex_scale_out.yaml @@ -0,0 +1,114 @@ +# Copyright (c) 2018 Intel Corporation +# +# 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. +{% set num_vnfs = num_vnfs or 1 %} +{% set availability_zone = availability_zone or {} %} +--- +schema: yardstick:task:0.1 +scenarios: +- type: NSPerf + traffic_profile: ../../traffic_profiles/ipv4_throughput_scale_out.yaml + topology: vfw_tg_topology_scale_out.yaml + extra_args: + num_vnfs: {{ num_vnfs }} + nodes: +{% for vnf_num in range(num_vnfs|int) %} + tg__{{ vnf_num }}: tg_{{ vnf_num }}.yardstick + vnf__{{ vnf_num }}: vnf_{{ vnf_num }}.yardstick +{% endfor %} + options: + framesize: + uplink: {64B: 100} + downlink: {64B: 100} + flow: + src_ip: +{% for vnf_num in range(num_vnfs|int) %} + - {'tg__{{ vnf_num }}': 'xe0'} +{% endfor %} + dst_ip: +{% for vnf_num in range(num_vnfs|int) %} + - {'tg__{{ vnf_num }}': 'xe1'} +{% endfor %} + count: 1 + traffic_type: 4 + rfc2544: + allowed_drop_rate: 0.0001 - 0.0001 +{% for vnf_num in range(num_vnfs|int) %} + vnf__{{ vnf_num }}: + rules: acl_1rule.yaml + vnf_config: {lb_config: 'SW', lb_count: 1, worker_config: '1C/1T', worker_threads: 1} +{% endfor %} + runner: + type: Iteration + iterations: 10 + interval: 35 +context: + # put node context first, so we don't HEAT deploy if node has errors + name: yardstick + image: yardstick-samplevnfs + flavor: + vcpus: 10 + ram: 20480 + disk: 6 + extra_specs: + hw:cpu_sockets: 1 + hw:cpu_cores: 10 + hw:cpu_threads: 1 + user: ubuntu + placement_groups: + pgrp1: + policy: "availability" + servers: +{% for vnf_num in range(num_vnfs|int) %} + vnf_{{ vnf_num }}: + floating_ip: true + placement: "pgrp1" + {% if 'vnf_%s'|format(vnf_num) in availability_zone %} + availability_zone: "{{ availability_zone['vnf_%s'|format(vnf_num)] }}" + {% endif %} + network_ports: + mgmt: + - mgmt + uplink_{{ vnf_num }}: + - xe0 + downlink_{{ vnf_num }}: + - xe1 + tg_{{ vnf_num }}: + floating_ip: true + placement: "pgrp1" + {% if 'tg_%s'|format(vnf_num) in availability_zone %} + availability_zone: "{{ availability_zone['tg_%s'|format(vnf_num)] }}" + {% endif %} + network_ports: + mgmt: + - mgmt + uplink_{{ vnf_num }}: + - xe0 + downlink_{{ vnf_num }}: + - xe1 +{% endfor %} + networks: + mgmt: + cidr: '10.0.1.0/24' +{% for vnf_num in range(num_vnfs|int) %} + uplink_{{ vnf_num }}: + cidr: '10.0.{{ (vnf_num * 2) + 2 }}.0/24' + gateway_ip: 'null' + port_security_enabled: False + enable_dhcp: 'false' + downlink_{{ vnf_num }}: + cidr: '10.0.{{ (vnf_num * 2) + 3 }}.0/24' + gateway_ip: 'null' + port_security_enabled: False + enable_dhcp: 'false' +{% endfor %} diff --git a/samples/vnf_samples/nsut/vfw/vfw_tg_topology_scale_out.yaml b/samples/vnf_samples/nsut/vfw/vfw_tg_topology_scale_out.yaml new file mode 100644 index 000000000..8bd01b7f2 --- /dev/null +++ b/samples/vnf_samples/nsut/vfw/vfw_tg_topology_scale_out.yaml @@ -0,0 +1,53 @@ +# Copyright (c) 2018 Intel Corporation +# +# 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. +{% set num_vnfs = get(extra_args, 'num_vnfs', 1) %} +--- +nsd:nsd-catalog: + nsd: + - id: 3tg-topology + name: 3tg-topology + short-name: 3tg-topology + description: 3tg-topology + constituent-vnfd: +{% for vnf_num in range(num_vnfs|int) %} + - member-vnf-index: '{{ (vnf_num * 2) + 1 }}' + vnfd-id-ref: tg__{{ vnf_num }} + VNF model: ../../vnf_descriptors/tg_rfc2544_tpl.yaml + - member-vnf-index: '{{ (vnf_num * 2) + 2 }}' + vnfd-id-ref: vnf__{{ vnf_num }} + VNF model: ../../vnf_descriptors/vfw_vnf.yaml +{% endfor %} + vld: +{% for vnf_num in range(num_vnfs|int) %} + - id: uplink_{{ vnf_num }} + name: tg__{{ vnf_num }} to vnf__{{ vnf_num }} link {{ (vnf_num * 2) + 1 }} + type: ELAN + vnfd-connection-point-ref: + - member-vnf-index-ref: '{{ (vnf_num * 2) + 1 }}' + vnfd-connection-point-ref: xe0 + vnfd-id-ref: tg__{{ vnf_num }} + - member-vnf-index-ref: '{{ (vnf_num * 2) + 2 }}' + vnfd-connection-point-ref: xe0 + vnfd-id-ref: vnf__{{ vnf_num }} + - id: downlink_{{ vnf_num }} + name: vnf__{{ vnf_num }} to tg__{{ vnf_num }} link {{ (vnf_num * 2) + 2 }} + type: ELAN + vnfd-connection-point-ref: + - member-vnf-index-ref: '{{ (vnf_num * 2) + 2 }}' + vnfd-connection-point-ref: xe1 + vnfd-id-ref: vnf__{{ vnf_num }} + - member-vnf-index-ref: '{{ (vnf_num * 2) + 1 }}' + vnfd-connection-point-ref: xe1 + vnfd-id-ref: tg__{{ vnf_num }} +{% endfor %} diff --git a/samples/vnf_samples/traffic_profiles/ipv4_throughput-10.yaml b/samples/vnf_samples/traffic_profiles/ipv4_throughput-10.yaml index f862abdb7..98b1bf96d 100644 --- a/samples/vnf_samples/traffic_profiles/ipv4_throughput-10.yaml +++ b/samples/vnf_samples/traffic_profiles/ipv4_throughput-10.yaml @@ -43,8 +43,7 @@ description: Traffic profile to run RFC2544 latency traffic_profile: traffic_type: RFC2544Profile # defines traffic behavior - constant or look for highest possible throughput frame_rate: 100 # pc of linerate - # that specifies a range (e.g. ipv4 address, port) - + duration: {{ duration }} uplink_0: ipv4: diff --git a/samples/vnf_samples/traffic_profiles/ipv4_throughput-2.yaml b/samples/vnf_samples/traffic_profiles/ipv4_throughput-2.yaml index a3218879b..ee0415371 100644 --- a/samples/vnf_samples/traffic_profiles/ipv4_throughput-2.yaml +++ b/samples/vnf_samples/traffic_profiles/ipv4_throughput-2.yaml @@ -43,8 +43,7 @@ description: Traffic profile to run RFC2544 latency traffic_profile: traffic_type: RFC2544Profile # defines traffic behavior - constant or look for highest possible throughput frame_rate: 100 # pc of linerate - # that specifies a range (e.g. ipv4 address, port) - + duration: {{ duration }} uplink_0: ipv4: diff --git a/samples/vnf_samples/traffic_profiles/ipv4_throughput-3.yaml b/samples/vnf_samples/traffic_profiles/ipv4_throughput-3.yaml index d849ed8ab..19f083646 100644 --- a/samples/vnf_samples/traffic_profiles/ipv4_throughput-3.yaml +++ b/samples/vnf_samples/traffic_profiles/ipv4_throughput-3.yaml @@ -43,8 +43,7 @@ description: Traffic profile to run RFC2544 latency traffic_profile: traffic_type: RFC2544Profile # defines traffic behavior - constant or look for highest possible throughput frame_rate: 100 # pc of linerate - # that specifies a range (e.g. ipv4 address, port) - + duration: {{ duration }} uplink_0: ipv4: diff --git a/samples/vnf_samples/traffic_profiles/ipv4_throughput-4.yaml b/samples/vnf_samples/traffic_profiles/ipv4_throughput-4.yaml index c03b28d60..95fa0b6d8 100644 --- a/samples/vnf_samples/traffic_profiles/ipv4_throughput-4.yaml +++ b/samples/vnf_samples/traffic_profiles/ipv4_throughput-4.yaml @@ -43,8 +43,7 @@ description: Traffic profile to run RFC2544 latency traffic_profile: traffic_type: RFC2544Profile # defines traffic behavior - constant or look for highest possible throughput frame_rate: 100 # pc of linerate - # that specifies a range (e.g. ipv4 address, port) - + duration: {{ duration }} uplink_0: ipv4: diff --git a/samples/vnf_samples/traffic_profiles/ipv4_throughput-cgnapt-ixia-scale-out.yaml b/samples/vnf_samples/traffic_profiles/ipv4_throughput-cgnapt-ixia-scale-out.yaml index ad703f291..43f52094a 100644 --- a/samples/vnf_samples/traffic_profiles/ipv4_throughput-cgnapt-ixia-scale-out.yaml +++ b/samples/vnf_samples/traffic_profiles/ipv4_throughput-cgnapt-ixia-scale-out.yaml @@ -44,8 +44,7 @@ description: Traffic profile to run RFC2544 latency traffic_profile: traffic_type: IXIARFC2544Profile # defines traffic behavior - constant or look for highest possible throughput frame_rate: 100 # pc of linerate - # that specifies a range (e.g. ipv4 address, port) - + duration: {{ duration }} [% for vnf_num in range(num_vnfs|int) %] uplink_[[ vnf_num ]]: diff --git a/samples/vnf_samples/traffic_profiles/ipv4_throughput-cgnapt-scale-out.yaml b/samples/vnf_samples/traffic_profiles/ipv4_throughput-cgnapt-scale-out.yaml index 75927d40d..a025a6931 100644 --- a/samples/vnf_samples/traffic_profiles/ipv4_throughput-cgnapt-scale-out.yaml +++ b/samples/vnf_samples/traffic_profiles/ipv4_throughput-cgnapt-scale-out.yaml @@ -44,8 +44,7 @@ description: Traffic profile to run RFC2544 latency traffic_profile: traffic_type: RFC2544Profile # defines traffic behavior - constant or look for highest possible throughput frame_rate: 100 # pc of linerate - # that specifies a range (e.g. ipv4 address, port) - + duration: {{ duration }} [% for vnf_num in range(num_vnfs|int) %] uplink_[[ vnf_num ]]: diff --git a/samples/vnf_samples/traffic_profiles/ipv4_throughput-ixia-correlated-scale-out.yaml b/samples/vnf_samples/traffic_profiles/ipv4_throughput-ixia-correlated-scale-out.yaml index 500163205..081d630ac 100644 --- a/samples/vnf_samples/traffic_profiles/ipv4_throughput-ixia-correlated-scale-out.yaml +++ b/samples/vnf_samples/traffic_profiles/ipv4_throughput-ixia-correlated-scale-out.yaml @@ -44,8 +44,7 @@ description: Traffic profile to run RFC2544 latency traffic_profile: traffic_type: IXIARFC2544Profile # defines traffic behavior - constant or look for highest possible throughput frame_rate: 100 # pc of linerate - # that specifies a range (e.g. ipv4 address, port) - + duration: {{ duration }} [% for vnf_num in range(num_vnfs|int) %] uplink_[[ vnf_num ]]: diff --git a/samples/vnf_samples/traffic_profiles/ipv4_throughput-ixia-scale-out.yaml b/samples/vnf_samples/traffic_profiles/ipv4_throughput-ixia-scale-out.yaml index 78e5f516a..d93bf1145 100644 --- a/samples/vnf_samples/traffic_profiles/ipv4_throughput-ixia-scale-out.yaml +++ b/samples/vnf_samples/traffic_profiles/ipv4_throughput-ixia-scale-out.yaml @@ -44,8 +44,7 @@ description: Traffic profile to run RFC2544 latency traffic_profile: traffic_type: IXIARFC2544Profile # defines traffic behavior - constant or look for highest possible throughput frame_rate: 100 # pc of linerate - # that specifies a range (e.g. ipv4 address, port) - + duration: {{ duration }} [% for vnf_num in range(num_vnfs|int) %] uplink_[[ vnf_num ]]: diff --git a/samples/vnf_samples/traffic_profiles/ipv4_throughput-scale-out.yaml b/samples/vnf_samples/traffic_profiles/ipv4_throughput-scale-out.yaml index 73c41099f..0e842d48a 100644 --- a/samples/vnf_samples/traffic_profiles/ipv4_throughput-scale-out.yaml +++ b/samples/vnf_samples/traffic_profiles/ipv4_throughput-scale-out.yaml @@ -44,8 +44,7 @@ description: Traffic profile to run RFC2544 latency traffic_profile: traffic_type: RFC2544Profile # defines traffic behavior - constant or look for highest possible throughput frame_rate: 100 # pc of linerate - # that specifies a range (e.g. ipv4 address, port) - + duration: {{ duration }} [% for vnf_num in range(num_vnfs|int) %] uplink_[[ vnf_num ]]: diff --git a/samples/vnf_samples/traffic_profiles/ipv4_throughput-scale-up.yaml b/samples/vnf_samples/traffic_profiles/ipv4_throughput-scale-up.yaml index d2cc18c15..b9e0c8cd1 100644 --- a/samples/vnf_samples/traffic_profiles/ipv4_throughput-scale-up.yaml +++ b/samples/vnf_samples/traffic_profiles/ipv4_throughput-scale-up.yaml @@ -44,7 +44,8 @@ description: Traffic profile to run RFC2544 latency traffic_profile: traffic_type: RFC2544Profile # defines traffic behavior - constant or look for highest possible throughput frame_rate: 100 # pc of linerate - # that specifies a range (e.g. ipv4 address, port) + duration: {{ duration }} + {% set count = 0 %} {% for vport in range(vports|int) %} uplink_{{vport}}: diff --git a/samples/vnf_samples/traffic_profiles/ipv4_throughput.yaml b/samples/vnf_samples/traffic_profiles/ipv4_throughput.yaml index 5b5b4473b..c267e7677 100644 --- a/samples/vnf_samples/traffic_profiles/ipv4_throughput.yaml +++ b/samples/vnf_samples/traffic_profiles/ipv4_throughput.yaml @@ -42,8 +42,7 @@ description: Traffic profile to run RFC2544 latency traffic_profile: traffic_type : RFC2544Profile # defines traffic behavior - constant or look for highest possible throughput frame_rate : 100 # pc of linerate - # that specifies a range (e.g. ipv4 address, port) - + duration: {{ duration }} uplink_0: ipv4: diff --git a/samples/vnf_samples/traffic_profiles/ipv4_throughput_cgnapt-10.yaml b/samples/vnf_samples/traffic_profiles/ipv4_throughput_cgnapt-10.yaml index 80d0872d5..1ff47a5b8 100644 --- a/samples/vnf_samples/traffic_profiles/ipv4_throughput_cgnapt-10.yaml +++ b/samples/vnf_samples/traffic_profiles/ipv4_throughput_cgnapt-10.yaml @@ -43,8 +43,7 @@ description: Traffic profile to run RFC2544 latency traffic_profile: traffic_type: RFC2544Profile # defines traffic behavior - constant or look for highest possible throughput frame_rate: 100 # pc of linerate - # that specifies a range (e.g. ipv4 address, port) - + duration: {{ duration }} uplink_0: ipv4: diff --git a/samples/vnf_samples/traffic_profiles/ipv4_throughput_cgnapt-2.yaml b/samples/vnf_samples/traffic_profiles/ipv4_throughput_cgnapt-2.yaml index d6c9164a0..2b3e6f3d1 100644 --- a/samples/vnf_samples/traffic_profiles/ipv4_throughput_cgnapt-2.yaml +++ b/samples/vnf_samples/traffic_profiles/ipv4_throughput_cgnapt-2.yaml @@ -43,8 +43,7 @@ description: Traffic profile to run RFC2544 latency traffic_profile: traffic_type: RFC2544Profile # defines traffic behavior - constant or look for highest possible throughput frame_rate: 100 # pc of linerate - # that specifies a range (e.g. ipv4 address, port) - + duration: {{ duration }} uplink_0: ipv4: diff --git a/samples/vnf_samples/traffic_profiles/ipv4_throughput_cgnapt-4.yaml b/samples/vnf_samples/traffic_profiles/ipv4_throughput_cgnapt-4.yaml index 55610b048..7df0682ed 100644 --- a/samples/vnf_samples/traffic_profiles/ipv4_throughput_cgnapt-4.yaml +++ b/samples/vnf_samples/traffic_profiles/ipv4_throughput_cgnapt-4.yaml @@ -43,8 +43,7 @@ description: Traffic profile to run RFC2544 latency traffic_profile: traffic_type: RFC2544Profile # defines traffic behavior - constant or look for highest possible throughput frame_rate: 100 # pc of linerate - # that specifies a range (e.g. ipv4 address, port) - + duration: {{ duration }} uplink_0: ipv4: diff --git a/samples/vnf_samples/traffic_profiles/ipv4_throughput_cgnapt-scale-out.yaml b/samples/vnf_samples/traffic_profiles/ipv4_throughput_cgnapt-scale-out.yaml index d455bccea..82c487e1b 100644 --- a/samples/vnf_samples/traffic_profiles/ipv4_throughput_cgnapt-scale-out.yaml +++ b/samples/vnf_samples/traffic_profiles/ipv4_throughput_cgnapt-scale-out.yaml @@ -44,8 +44,7 @@ description: Traffic profile to run RFC2544 latency traffic_profile: traffic_type: RFC2544Profile # defines traffic behavior - constant or look for highest possible throughput frame_rate: 100 # pc of linerate - # that specifies a range (e.g. ipv4 address, port) - + duration: {{ duration }} [% for vnf_num in range(num_vnfs|int) %] uplink_[[ vnf_num ]]: diff --git a/samples/vnf_samples/traffic_profiles/ipv4_throughput_cgnapt.yaml b/samples/vnf_samples/traffic_profiles/ipv4_throughput_cgnapt.yaml index 61cbd4e4e..809415a00 100644 --- a/samples/vnf_samples/traffic_profiles/ipv4_throughput_cgnapt.yaml +++ b/samples/vnf_samples/traffic_profiles/ipv4_throughput_cgnapt.yaml @@ -42,8 +42,7 @@ description: Traffic profile to run RFC2544 latency traffic_profile: traffic_type : RFC2544Profile # defines traffic behavior - constant or look for highest possible throughput frame_rate : 100 # pc of linerate - # that specifies a range (e.g. ipv4 address, port) - + duration: {{ duration }} uplink_0: ipv4: diff --git a/samples/vnf_samples/traffic_profiles/ipv4_throughput_scale_out.yaml b/samples/vnf_samples/traffic_profiles/ipv4_throughput_scale_out.yaml new file mode 100644 index 000000000..71e9e817b --- /dev/null +++ b/samples/vnf_samples/traffic_profiles/ipv4_throughput_scale_out.yaml @@ -0,0 +1,102 @@ +# Copyright (c) 2018 Intel Corporation +# +# 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. + +# flow definition for ACL tests - 1K flows - ipv4 only +# +# the number of flows defines the widest range of parameters +# for example if srcip_range=1.0.0.1-1.0.0.255 and dst_ip_range=10.0.0.1-10.0.1.255 +# and it should define only 16 flows +# +#there is assumption that packets generated will have a random sequences of following addresses pairs +# in the packets +# 1. src=1.x.x.x(x.x.x =random from 1..255) dst=10.x.x.x (random from 1..512) +# 2. src=1.x.x.x(x.x.x =random from 1..255) dst=10.x.x.x (random from 1..512) +# ... +# 512. src=1.x.x.x(x.x.x =random from 1..255) dst=10.x.x.x (random from 1..512) +# +# not all combination should be filled +# Any other field with random range will be added to flow definition +# +# the example.yaml provides all possibilities for traffic generation +# +# the profile defines a public and private side to make limited traffic correlation +# between private and public side same way as it is made by IXIA solution. +# +{% set num_vnfs = get(extra_args, 'num_vnfs', 1) %} +--- +schema: "nsb:traffic_profile:0.1" +name: rfc2544 +description: Traffic profile to run RFC2544 latency +traffic_profile: + traffic_type : RFC2544Profile # defines traffic behavior - constant or look for highest possible throughput + frame_rate : 100 # pc of linerate + # that specifies a range (e.g. ipv4 address, port) +{% for vnf_num in range(num_vnfs|int) %} +uplink_{{ vnf_num }}: + ipv4: + id: {{ (vnf_num * 2) + 1 }} + outer_l2: + framesize: + 64B: "{{get(imix, 'imix.uplink.64B', '0') }}" + 128B: "{{get(imix, 'imix.uplink.128B', '0') }}" + 256B: "{{get(imix, 'imix.uplink.256B', '0') }}" + 373B: "{{get(imix, 'imix.uplink.373B', '0') }}" + 512B: "{{get(imix, 'imix.uplink.512B', '0') }}" + 570B: "{{get(imix, 'imix.uplink.570B', '0') }}" + 1024B: "{{get(imix, 'imix.uplink.1024B', '0') }}" + 1280B: "{{get(imix, 'imix.uplink.1280B', '0') }}" + 1400B: "{{get(imix, 'imix.uplink.1400B', '0') }}" + 1500B: "{{get(imix, 'imix.uplink.1500B', '0') }}" + 1518B: "{{get(imix, 'imix.uplink.1518B', '0') }}" + + outer_l3v4: + proto: "udp" + srcip4: "{{get(flow, 'flow.src_ip_{{ vnf_num }}', '10.0.2.1-10.0.2.255') }}" + dstip4: "{{get(flow, 'flow.dst_ip_{{ vnf_num }}', '10.0.3.1-10.0.3.255') }}" + count: "{{get(flow, 'flow.count', '1') }}" + ttl: 32 + dscp: 0 + outer_l4: + srcport: "{{get(flow, 'flow.src_port_{{ vnf_num }}', '1234-4321') }}" + dstport: "{{get(flow, 'flow.dst_port_{{ vnf_num }}', '2001-4001') }}" + count: "{{get(flow, 'flow.count', '1') }}" +downlink_{{ vnf_num }}: + ipv4: + id: {{ (vnf_num * 2) + 2 }} + outer_l2: + framesize: + 64B: "{{ get(imix, 'imix.downlink.64B', '0') }}" + 128B: "{{ get(imix, 'imix.downlink.128B', '0') }}" + 256B: "{{ get(imix, 'imix.downlink.256B', '0') }}" + 373b: "{{ get(imix, 'imix.downlink.373B', '0') }}" + 512B: "{{ get(imix, 'imix.downlink.512B', '0') }}" + 570B: "{{get(imix, 'imix.downlink.570B', '0') }}" + 1024B: "{{get(imix, 'imix.downlink.1024B', '0') }}" + 1280B: "{{get(imix, 'imix.downlink.1280B', '0') }}" + 1400B: "{{get(imix, 'imix.downlink.1400B', '0') }}" + 1500B: "{{get(imix, 'imix.downlink.1500B', '0') }}" + 1518B: "{{get(imix, 'imix.downlink.1518B', '0') }}" + + outer_l3v4: + proto: "udp" + srcip4: "{{get(flow, 'flow.dst_ip_{{ vnf_num }}', '10.0.3.1-10.0.3.255') }}" + dstip4: "{{get(flow, 'flow.src_ip_{{ vnf_num }}', '10.0.2.1-10.0.2.255') }}" + count: "{{get(flow, 'flow.count', '1') }}" + ttl: 32 + dscp: 0 + outer_l4: + srcport: "{{get(flow, 'flow.dst_port_{{ vnf_num }}', '1234-4321') }}" + dstport: "{{get(flow, 'flow.src_port_{{ vnf_num }}', '2001-4001') }}" + count: "{{get(flow, 'flow.count', '1') }}" +{% endfor %} diff --git a/samples/vnf_samples/traffic_profiles/ipv4_throughput_vpe.yaml b/samples/vnf_samples/traffic_profiles/ipv4_throughput_vpe.yaml index 20bc6568d..e113c9de2 100644 --- a/samples/vnf_samples/traffic_profiles/ipv4_throughput_vpe.yaml +++ b/samples/vnf_samples/traffic_profiles/ipv4_throughput_vpe.yaml @@ -42,8 +42,7 @@ description: Traffic profile to run RFC2544 latency traffic_profile: traffic_type : RFC2544Profile # defines traffic behavior - constant or look for highest possible throughput frame_rate : 100 # pc of linerate - # that specifies a range (e.g. ipv4 address, port) - + duration: {{ duration }} uplink_0: ipv4: diff --git a/samples/vnf_samples/traffic_profiles/ixia_ipv4_latency.yaml b/samples/vnf_samples/traffic_profiles/ixia_ipv4_latency.yaml index 7b66d663b..507491446 100644 --- a/samples/vnf_samples/traffic_profiles/ixia_ipv4_latency.yaml +++ b/samples/vnf_samples/traffic_profiles/ixia_ipv4_latency.yaml @@ -28,8 +28,7 @@ description: Traffic profile to run RFC2544 latency traffic_profile: traffic_type : IXIARFC2544Profile # defines traffic behavior - constant or look for highest possible throughput frame_rate : 100 # pc of linerate - # that specifies a range (e.g. ipv4 address, port) - + duration: {{ duration }} uplink_0: ipv4: @@ -53,12 +52,14 @@ uplink_0: srcip4: "{{get(flow, 'flow.src_ip_0', '1.1.1.1-1.15.255.255') }}" dstip4: "{{get(flow, 'flow.dst_ip_0', '90.90.1.1-90.105.255.255') }}" count: "{{get(flow, 'flow.count', '1') }}" + seed: "{{get(flow, 'flow.seed', '1') }}" ttl: 32 dscp: 0 outer_l4: srcport: "{{get(flow, 'flow.src_port_0', '1234') }}" dstport: "{{get(flow, 'flow.dst_port_0', '2001') }}" count: "{{get(flow, 'flow.count', '1') }}" + seed: "{{get(flow, 'flow.seed', '1') }}" downlink_0: ipv4: id: 2 @@ -84,12 +85,14 @@ downlink_0: dstip4: "{{get(flow, 'flow.public_ip_0', '90.90.1.1-90.105.255.255') }}" {% endif %} count: "{{get(flow, 'flow.count', '1') }}" + seed: "{{get(flow, 'flow.seed', '1') }}" ttl: 32 dscp: 0 outer_l4: srcport: "{{get(flow, 'flow.src_port_0', '1234') }}" dstport: "{{get(flow, 'flow.dst_port_0', '2001') }}" count: "{{get(flow, 'flow.count', '1') }}" + seed: "{{get(flow, 'flow.seed', '1') }}" uplink_1: ipv4: id: 3 @@ -112,12 +115,14 @@ uplink_1: srcip4: "{{get(flow, 'flow.src_ip_1', '1.1.1.1-1.15.255.255') }}" dstip4: "{{get(flow, 'flow.dst_ip_1', '90.90.1.1-90.105.255.255') }}" count: "{{get(flow, 'flow.count', '1') }}" + seed: "{{get(flow, 'flow.seed', '1') }}" ttl: 32 dscp: 0 outer_l4: srcport: "{{get(flow, 'flow.src_port_1', '1234') }}" dstport: "{{get(flow, 'flow.dst_port_1', '2001') }}" count: "{{get(flow, 'flow.count', '1') }}" + seed: "{{get(flow, 'flow.seed', '1') }}" downlink_1: ipv4: id: 4 @@ -143,9 +148,11 @@ downlink_1: dstip4: "{{get(flow, 'flow.public_ip_1', '90.90.1.1-90.105.255.255') }}" {% endif %} count: "{{get(flow, 'flow.count', '1') }}" + seed: "{{get(flow, 'flow.seed', '1') }}" ttl: 32 dscp: 0 outer_l4: srcport: "{{get(flow, 'flow.dst_port_1', '1234') }}" dstport: "{{get(flow, 'flow.src_port_1', '2001') }}" count: "{{get(flow, 'flow.count', '1') }}" + seed: "{{get(flow, 'flow.seed', '1') }}" diff --git a/samples/vnf_samples/traffic_profiles/ixia_ipv4_latency_cgnapt.yaml b/samples/vnf_samples/traffic_profiles/ixia_ipv4_latency_cgnapt.yaml index 8fdfe9b2f..3cbd7cd62 100644 --- a/samples/vnf_samples/traffic_profiles/ixia_ipv4_latency_cgnapt.yaml +++ b/samples/vnf_samples/traffic_profiles/ixia_ipv4_latency_cgnapt.yaml @@ -28,8 +28,7 @@ description: Traffic profile to run RFC2544 latency traffic_profile: traffic_type : IXIARFC2544Profile # defines traffic behavior - constant or look for highest possible throughput frame_rate : 100 # pc of linerate - # that specifies a range (e.g. ipv4 address, port) - + duration: {{ duration }} uplink_0: ipv4: @@ -51,12 +50,14 @@ uplink_0: srcip4: "{{get(flow, 'flow.src_ip_0', '1.1.1.1-1.15.255.255') }}" dstip4: "{{get(flow, 'flow.dst_ip_0', '90.90.1.1-90.105.255.255') }}" count: "{{get(flow, 'flow.count', '1') }}" + seed: "{{get(flow, 'flow.seed', '1') }}" ttl: 32 dscp: 0 outer_l4: srcport: "{{get(flow, 'flow.src_port_0', '1234') }}" dstport: "{{get(flow, 'flow.dst_port_0', '2001') }}" count: "{{get(flow, 'flow.count', '1') }}" + seed: "{{get(flow, 'flow.seed', '1') }}" downlink_0: ipv4: id: 2 @@ -77,12 +78,14 @@ downlink_0: srcip4: "{{get(flow, 'flow.dst_ip_0', '1.1.1.1-1.15.255.255') }}" dstip4: "{{get(flow, 'flow.public_ip_0', '10.0.2.1-10.0.2.255') }}" count: "{{get(flow, 'flow.count', '1') }}" + seed: "{{get(flow, 'flow.seed', '1') }}" ttl: 32 dscp: 0 outer_l4: srcport: "{{get(flow, 'flow.src_port_0', '1234') }}" dstport: "{{get(flow, 'flow.dst_port_0', '2001') }}" count: "{{get(flow, 'flow.count', '1') }}" + seed: "{{get(flow, 'flow.seed', '1') }}" uplink_1: ipv4: id: 3 @@ -103,12 +106,14 @@ uplink_1: srcip4: "{{get(flow, 'flow.src_ip_1', '1.1.1.1-1.15.255.255') }}" dstip4: "{{get(flow, 'flow.dst_ip_1', '90.90.1.1-90.105.255.255') }}" count: "{{get(flow, 'flow.count', '1') }}" + seed: "{{get(flow, 'flow.seed', '1') }}" ttl: 32 dscp: 0 outer_l4: srcport: "{{get(flow, 'flow.src_port_1', '1234') }}" dstport: "{{get(flow, 'flow.dst_port_1', '2001') }}" count: "{{get(flow, 'flow.count', '1') }}" + seed: "{{get(flow, 'flow.seed', '1') }}" downlink_1: ipv4: id: 4 @@ -129,9 +134,11 @@ downlink_1: srcip4: "{{get(flow, 'flow.dst_ip_1', '1.1.1.1-1.15.255.255') }}" dstip4: "{{get(flow, 'flow.public_ip_1', '10.0.2.1-10.0.2.255') }}" count: "{{get(flow, 'flow.count', '1') }}" + seed: "{{get(flow, 'flow.seed', '1') }}" ttl: 32 dscp: 0 outer_l4: srcport: "{{get(flow, 'flow.dst_port_1', '1234') }}" dstport: "{{get(flow, 'flow.src_port_1', '2001') }}" count: "{{get(flow, 'flow.count', '1') }}" + seed: "{{get(flow, 'flow.seed', '1') }}" diff --git a/samples/vnf_samples/traffic_profiles/ixia_ipv4_latency_vpe.yaml b/samples/vnf_samples/traffic_profiles/ixia_ipv4_latency_vpe.yaml index 4d73b8ffe..edff3612e 100644 --- a/samples/vnf_samples/traffic_profiles/ixia_ipv4_latency_vpe.yaml +++ b/samples/vnf_samples/traffic_profiles/ixia_ipv4_latency_vpe.yaml @@ -42,7 +42,7 @@ description: Traffic profile to run RFC2544 latency traffic_profile: traffic_type : IXIARFC2544Profile # defines traffic behavior - constant or look for highest possible throughput frame_rate : 100 # pc of linerate - # that specifies a range (e.g. ipv4 address, port) + injection_time: {{ injection_time }} uplink_0: ipv4: @@ -72,6 +72,7 @@ uplink_0: srcip4: "{{get(flow, 'flow.src_ip_0', '192.168.0.0-192.168.255.255') }}" dstip4: "{{get(flow, 'flow.dst_ip_0', '192.16.0.0-192.16.0.31') }}" count: "{{get(flow, 'flow.count', '1') }}" + seed: "{{get(flow, 'flow.seed', '1') }}" ttl: 32 dscp: 32 @@ -79,6 +80,7 @@ uplink_0: srcport: "{{get(flow, 'flow.src_port_0', '0') }}" dstport: "{{get(flow, 'flow.dst_port_0', '0') }}" count: "{{get(flow, 'flow.count', '1') }}" + seed: "{{get(flow, 'flow.seed', '1') }}" downlink_0: id: 2 ipv4: @@ -97,6 +99,7 @@ downlink_0: srcip4: "{{get(flow, 'flow.dst_ip_0', '192.16.0.0-192.16.0.31') }}" dstip4: "{{get(flow, 'flow.src_ip_0', '192.168.0.0-192.168.255.255') }}" count: "{{get(flow, 'flow.count', '1') }}" + seed: "{{get(flow, 'flow.seed', '1') }}" ttl: 32 dscp: 32 @@ -104,6 +107,7 @@ downlink_0: srcport: "{{get(flow, 'flow.dst_port_0', '0') }}" dstport: "{{get(flow, 'flow.src_port_0', '0') }}" count: "{{get(flow, 'flow.count', '1') }}" + seed: "{{get(flow, 'flow.seed', '1') }}" uplink_1: id: 3 ipv4: @@ -131,6 +135,8 @@ uplink_1: proto: "tcp" srcip4: "{{get(flow, 'flow.srcip_1', '192.168.0.0-192.168.255.255') }}" dstip4: "{{get(flow, 'flow.dstip_1', '192.16.0.0-192.16.0.31') }}" + count: "{{get(flow, 'flow.count', '1') }}" + seed: "{{get(flow, 'flow.seed', '1') }}" ttl: 32 dscp: 32 @@ -138,6 +144,7 @@ uplink_1: srcport: "{{get(flow, 'flow.src_port_1', '0') }}" dstport: "{{get(flow, 'flow.dst_port_1', '0') }}" count: "{{get(flow, 'flow.count', '1') }}" + seed: "{{get(flow, 'flow.seed', '1') }}" downlink_1: id: 4 ipv4: @@ -156,6 +163,7 @@ downlink_1: srcip4: "{{get(flow, 'flow.dst_ip_1', '192.16.0.0-192.16.0.31') }}" dstip4: "{{get(flow, 'flow.src_ip_1', '192.168.0.0-192.168.255.255') }}" count: "{{get(flow, 'flow.count', '1') }}" + seed: "{{get(flow, 'flow.seed', '1') }}" ttl: 32 dscp: 32 @@ -163,3 +171,4 @@ downlink_1: srcport: "{{get(flow, 'flow.dst_port_1', '0') }}" dstport: "{{get(flow, 'flow.src_port_1', '0') }}" count: "{{get(flow, 'flow.count', '1') }}" + seed: "{{get(flow, 'flow.seed', '1') }}" diff --git a/tests/unit/__init__.py b/samples/vnf_samples/traffic_profiles/pktgen_throughput.yaml index 5935abbac..e222e1d8c 100644 --- a/tests/unit/__init__.py +++ b/samples/vnf_samples/traffic_profiles/pktgen_throughput.yaml @@ -1,20 +1,21 @@ -# Copyright (c) 2017 Intel Corporation
-#
-# 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.
-
-from yardstick import tests
-
-
-# NOTE(ralonsoh): to be removed. Replace all occurrences of
-# tests.unit.STL_MOCKS with yardstick.tests.STL_MOCKS
-STL_MOCKS = tests.STL_MOCKS
+# Copyright (c) 2018 Intel Corporation +# +# 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. +--- +schema: "nsb:traffic_profile:0.1" + +name: pktgen +description: Traffic profile to run throughput tests +traffic_profile: + traffic_type: PktgenTrafficProfile + duration: 15 diff --git a/samples/vnf_samples/traffic_profiles/prox_bng.yaml b/samples/vnf_samples/traffic_profiles/prox_bng.yaml index 59d10f0b3..6705fb1f7 100644 --- a/samples/vnf_samples/traffic_profiles/prox_bng.yaml +++ b/samples/vnf_samples/traffic_profiles/prox_bng.yaml @@ -19,7 +19,7 @@ description: Prox BNG traffic profile traffic_profile: traffic_type: ProxBinSearchProfile - tolerated_loss: 100.0 #0.001 + tolerated_loss: 5 test_precision: 0.01 # The minimum size of the Ethernet frame for the BNG test is 78 bytes. packet_sizes: [78] diff --git a/samples/vnf_samples/traffic_profiles/prox_vpe.yaml b/samples/vnf_samples/traffic_profiles/prox_vpe.yaml index 7aab8dd3b..c9aec0e44 100644 --- a/samples/vnf_samples/traffic_profiles/prox_vpe.yaml +++ b/samples/vnf_samples/traffic_profiles/prox_vpe.yaml @@ -19,11 +19,11 @@ description: Prox vPE traffic profile traffic_profile: traffic_type: ProxBinSearchProfile - tolerated_loss: 100.0 #0.001 - test_precision: 0.01 + tolerated_loss: 0.001 #0.001 + test_precision: 0.1 # The minimum size of the Ethernet frame for the vPE test is 68 bytes. packet_sizes: [68] - duration: 5 + duration: 60 lower_bound: 0.0 upper_bound: 100.0 diff --git a/samples/vnf_samples/vnf_descriptors/tg_pktgen.yaml b/samples/vnf_samples/vnf_descriptors/tg_pktgen.yaml new file mode 100644 index 000000000..17e631652 --- /dev/null +++ b/samples/vnf_samples/vnf_descriptors/tg_pktgen.yaml @@ -0,0 +1,47 @@ +# Copyright (c) 2018 Intel Corporation +# +# 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. +--- +vnfd:vnfd-catalog: + vnfd: + - id: PktgenTrafficGen # NSB class mapping + name: pktgen_tg + short-name: pktgen_tg + description: Pktgen DPDK traffic generator + mgmt-interface: + vdu-id: pktgen + {% if ip is defined %} + ip: '{{ ip }}' + {% endif %} + {% if service_ports is defined and service_ports %} + service_ports: + {% for port in service_ports %} + - port: "{{ port['port']|int }}" + node_port: "{{ port['node_port']|int }}" + target_port: "{{ port['target_port']|int }}" + {% endfor %} + {% endif %} + + vdu: + - id: pktgen_tg + name: pktgen_tg + description: Pktgen DPDK traffic generator + + benchmark: + kpi: + - rx_throughput_fps + - tx_throughput_fps + - tx_throughput_mbps + - rx_throughput_mbps + - in_packets + - out_packets diff --git a/test-requirements.txt b/test-requirements.txt index 4828e98b0..7825cc5d2 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -14,8 +14,8 @@ testtools==2.3.0 # OSI Approved MIT License unittest2==1.1.0 # OSI Approved BSD License # NOTE(ralonsoh): to be removed, only for coverage support -python-heatclient==1.8.1 # OSI Approved Apache Software License +python-heatclient==1.11.0 # OSI Approved Apache Software License -# Yardstick F release <-> OpenStack Pike release -openstack_requirements==1.1.0 # OSI Approved Apache Software License --e git+https://github.com/openstack/requirements.git@stable/pike#egg=os_requirements +# Yardstick G release <-> OpenStack Queens release +openstack_requirements==1.2.0 # OSI Approved Apache Software License +-e git+https://github.com/openstack/requirements.git@stable/queens#egg=os_requirements diff --git a/tests/ci/load_images.sh b/tests/ci/load_images.sh index 1e1591ce3..7a86abb4e 100755 --- a/tests/ci/load_images.sh +++ b/tests/ci/load_images.sh @@ -29,11 +29,6 @@ if [ "${INSTALLER_TYPE}" == 'fuel' ]; then fi export YARD_IMG_ARCH -HW_FW_TYPE="" -if [ "${YARD_IMG_ARCH}" == "arm64" ]; then - HW_FW_TYPE=uefi -fi -export HW_FW_TYPE UCA_HOST="cloud-images.ubuntu.com" if [ "${YARD_IMG_ARCH}" == "arm64" ]; then @@ -104,18 +99,12 @@ load_yardstick_image() echo echo "========== Loading yardstick cloud image ==========" EXTRA_PARAMS="" - if [[ "${YARD_IMG_ARCH}" == "arm64" ]]; then - EXTRA_PARAMS="--property hw_video_model=vga" - fi # VPP requires guest memory to be backed by large pages if [[ "$DEPLOY_SCENARIO" == *"-fdio-"* ]]; then EXTRA_PARAMS=$EXTRA_PARAMS" --property hw_mem_page_size=large" fi - if [[ -n "${HW_FW_TYPE}" ]]; then - EXTRA_PARAMS=$EXTRA_PARAMS" --property hw_firmware_type=${HW_FW_TYPE}" - fi if [[ "$DEPLOY_SCENARIO" == *"-lxd-"* ]]; then output=$(eval openstack ${SECURE} image create \ @@ -165,7 +154,7 @@ load_cirros_image() if [[ "${YARD_IMG_ARCH}" == "arm64" ]]; then CIRROS_IMAGE_VERSION="cirros-d161201" CIRROS_IMAGE_PATH="/home/opnfv/images/cirros-d161201-aarch64-disk.img" - EXTRA_PARAMS="--property hw_video_model=vga --property short_id=ubuntu16.04" + EXTRA_PARAMS="--property short_id=ubuntu16.04" else CIRROS_IMAGE_VERSION="cirros-0.3.5" CIRROS_IMAGE_PATH="/home/opnfv/images/cirros-0.3.5-x86_64-disk.img" @@ -184,9 +173,6 @@ load_cirros_image() EXTRA_PARAMS=$EXTRA_PARAMS" --property hw_mem_page_size=large" fi - if [[ -n "${HW_FW_TYPE}" ]]; then - EXTRA_PARAMS=$EXTRA_PARAMS" --property hw_firmware_type=${HW_FW_TYPE}" - fi output=$(openstack ${SECURE} image create \ --disk-format qcow2 \ diff --git a/tests/opnfv/test_cases/opnfv_yardstick_tc001.yaml b/tests/opnfv/test_cases/opnfv_yardstick_tc001.yaml index 4faa0bc5a..8bfe44693 100644 --- a/tests/opnfv/test_cases/opnfv_yardstick_tc001.yaml +++ b/tests/opnfv/test_cases/opnfv_yardstick_tc001.yaml @@ -62,7 +62,7 @@ context: networks: test: cidr: '10.0.1.0/24' - {% if provider == "vlan" %} + {% if provider == "vlan" or provider == "sriov" %} provider: {{provider}} physical_network: {{physical_network}} {% if segmentation_id %} diff --git a/tests/opnfv/test_cases/opnfv_yardstick_tc002.yaml b/tests/opnfv/test_cases/opnfv_yardstick_tc002.yaml index 7f8c22943..596db25bb 100644 --- a/tests/opnfv/test_cases/opnfv_yardstick_tc002.yaml +++ b/tests/opnfv/test_cases/opnfv_yardstick_tc002.yaml @@ -59,7 +59,7 @@ context: networks: test: cidr: '10.0.1.0/24' - {% if provider == "vlan" %} + {% if provider == "vlan" or provider == "sriov" %} provider: {{provider}} physical_network: {{physical_network}} {% if segmentation_id %} diff --git a/tests/opnfv/test_cases/opnfv_yardstick_tc005.yaml b/tests/opnfv/test_cases/opnfv_yardstick_tc005.yaml index 101c4210e..756c14d86 100644 --- a/tests/opnfv/test_cases/opnfv_yardstick_tc005.yaml +++ b/tests/opnfv/test_cases/opnfv_yardstick_tc005.yaml @@ -60,7 +60,7 @@ context: networks: test: cidr: '10.0.1.0/24' - {% if provider == "vlan" %} + {% if provider == "vlan" or provider == "sriov" %} provider: {{provider}} physical_network: {{physical_network}} {% if segmentation_id %} diff --git a/tests/opnfv/test_cases/opnfv_yardstick_tc006.yaml b/tests/opnfv/test_cases/opnfv_yardstick_tc006.yaml index fe244e81c..cf124360e 100644 --- a/tests/opnfv/test_cases/opnfv_yardstick_tc006.yaml +++ b/tests/opnfv/test_cases/opnfv_yardstick_tc006.yaml @@ -64,7 +64,7 @@ context: networks: test: cidr: '10.0.1.0/24' - {% if provider == "vlan" %} + {% if provider == "vlan" or provider == "sriov" %} provider: {{provider}} physical_network: {{physical_network}} {% if segmentation_id %} diff --git a/tests/opnfv/test_cases/opnfv_yardstick_tc008.yaml b/tests/opnfv/test_cases/opnfv_yardstick_tc008.yaml index 22e576015..c905302e2 100644 --- a/tests/opnfv/test_cases/opnfv_yardstick_tc008.yaml +++ b/tests/opnfv/test_cases/opnfv_yardstick_tc008.yaml @@ -78,13 +78,10 @@ context: networks: test: cidr: '10.0.1.0/24' - {% if provider == "vlan" %} + {% if provider == "vlan" or provider == "sriov" %} provider: {{provider}} physical_network: {{physical_network}} {% if segmentation_id %} segmentation_id: {{segmentation_id}} {% endif %} {% endif %} - #test-sriov: - #cidr: '10.0.1.0/24' - #provider: "sriov" diff --git a/tests/opnfv/test_cases/opnfv_yardstick_tc009.yaml b/tests/opnfv/test_cases/opnfv_yardstick_tc009.yaml index 3c5f72d5a..cefa50541 100644 --- a/tests/opnfv/test_cases/opnfv_yardstick_tc009.yaml +++ b/tests/opnfv/test_cases/opnfv_yardstick_tc009.yaml @@ -64,7 +64,7 @@ context: networks: test: cidr: '10.0.1.0/24' - {% if provider == "vlan" %} + {% if provider == "vlan" or provider == "sriov" %} provider: {{provider}} physical_network: {{physical_network}} {% if segmentation_id %} diff --git a/tests/opnfv/test_cases/opnfv_yardstick_tc010.yaml b/tests/opnfv/test_cases/opnfv_yardstick_tc010.yaml index cf9706847..e84e1135c 100644 --- a/tests/opnfv/test_cases/opnfv_yardstick_tc010.yaml +++ b/tests/opnfv/test_cases/opnfv_yardstick_tc010.yaml @@ -49,7 +49,7 @@ context: networks: test: cidr: '10.0.1.0/24' - {% if provider == "vlan" %} + {% if provider == "vlan" or provider == "sriov" %} provider: {{provider}} physical_network: {{physical_network}} {% if segmentation_id %} diff --git a/tests/opnfv/test_cases/opnfv_yardstick_tc011.yaml b/tests/opnfv/test_cases/opnfv_yardstick_tc011.yaml index ee36c6c82..998002249 100644 --- a/tests/opnfv/test_cases/opnfv_yardstick_tc011.yaml +++ b/tests/opnfv/test_cases/opnfv_yardstick_tc011.yaml @@ -61,7 +61,7 @@ context: networks: test: cidr: '10.0.1.0/24' - {% if provider == "vlan" %} + {% if provider == "vlan" or provider == "sriov" %} provider: {{provider}} physical_network: {{physical_network}} {% if segmentation_id %} diff --git a/tests/opnfv/test_cases/opnfv_yardstick_tc012.yaml b/tests/opnfv/test_cases/opnfv_yardstick_tc012.yaml index b8b208f12..a1058bc3b 100644 --- a/tests/opnfv/test_cases/opnfv_yardstick_tc012.yaml +++ b/tests/opnfv/test_cases/opnfv_yardstick_tc012.yaml @@ -50,7 +50,7 @@ context: networks: test: cidr: '10.0.1.0/24' - {% if provider == "vlan" %} + {% if provider == "vlan" or provider == "sriov" %} provider: {{provider}} physical_network: {{physical_network}} {% if segmentation_id %} diff --git a/tests/opnfv/test_cases/opnfv_yardstick_tc014.yaml b/tests/opnfv/test_cases/opnfv_yardstick_tc014.yaml index bd0fe3627..78c9e850c 100644 --- a/tests/opnfv/test_cases/opnfv_yardstick_tc014.yaml +++ b/tests/opnfv/test_cases/opnfv_yardstick_tc014.yaml @@ -43,7 +43,7 @@ context: networks: test: cidr: '10.0.1.0/24' - {% if provider == "vlan" %} + {% if provider == "vlan" or provider == "sriov" %} provider: {{provider}} physical_network: {{physical_network}} {% if segmentation_id %} diff --git a/tests/opnfv/test_cases/opnfv_yardstick_tc023.yaml b/tests/opnfv/test_cases/opnfv_yardstick_tc023.yaml index 7136a9e7e..c2c176b87 100644 --- a/tests/opnfv/test_cases/opnfv_yardstick_tc023.yaml +++ b/tests/opnfv/test_cases/opnfv_yardstick_tc023.yaml @@ -181,7 +181,7 @@ contexts: networks: test: cidr: '10.0.1.0/24' - {% if provider == "vlan" %} + {% if provider == "vlan" or provider == "sriov" %} provider: {{provider}} physical_network: {{physical_network}} {% if segmentation_id %} diff --git a/tests/opnfv/test_cases/opnfv_yardstick_tc037.yaml b/tests/opnfv/test_cases/opnfv_yardstick_tc037.yaml index 3622b40d7..a6cf6a292 100644 --- a/tests/opnfv/test_cases/opnfv_yardstick_tc037.yaml +++ b/tests/opnfv/test_cases/opnfv_yardstick_tc037.yaml @@ -95,7 +95,7 @@ context: networks: test: cidr: '10.0.1.0/24' - {% if provider == "vlan" %} + {% if provider == "vlan" or provider == "sriov" %} provider: {{provider}} physical_network: {{physical_network}} {% if segmentation_id %} diff --git a/tests/opnfv/test_cases/opnfv_yardstick_tc038.yaml b/tests/opnfv/test_cases/opnfv_yardstick_tc038.yaml index 59fb95d07..2250ae589 100644 --- a/tests/opnfv/test_cases/opnfv_yardstick_tc038.yaml +++ b/tests/opnfv/test_cases/opnfv_yardstick_tc038.yaml @@ -95,7 +95,7 @@ context: networks: test: cidr: '10.0.1.0/24' - {% if provider == "vlan" %} + {% if provider == "vlan" or provider == "sriov" %} provider: {{provider}} physical_network: {{physical_network}} {% if segmentation_id %} diff --git a/tests/opnfv/test_cases/opnfv_yardstick_tc069.yaml b/tests/opnfv/test_cases/opnfv_yardstick_tc069.yaml index 2a4082310..3bfaff961 100644 --- a/tests/opnfv/test_cases/opnfv_yardstick_tc069.yaml +++ b/tests/opnfv/test_cases/opnfv_yardstick_tc069.yaml @@ -49,7 +49,7 @@ context: networks: test: cidr: '10.0.1.0/24' - {% if provider == "vlan" %} + {% if provider == "vlan" or provider == "sriov" %} provider: {{provider}} physical_network: {{physical_network}} {% if segmentation_id %} diff --git a/tests/opnfv/test_cases/opnfv_yardstick_tc070.yaml b/tests/opnfv/test_cases/opnfv_yardstick_tc070.yaml index 7ea10d8a4..8cbd24747 100644 --- a/tests/opnfv/test_cases/opnfv_yardstick_tc070.yaml +++ b/tests/opnfv/test_cases/opnfv_yardstick_tc070.yaml @@ -97,7 +97,7 @@ context: networks: test: cidr: '10.0.1.0/24' - {% if provider == "vlan" %} + {% if provider == "vlan" or provider == "sriov" %} provider: {{provider}} physical_network: {{physical_network}} {% if segmentation_id %} diff --git a/tests/opnfv/test_cases/opnfv_yardstick_tc071.yaml b/tests/opnfv/test_cases/opnfv_yardstick_tc071.yaml index b6a944bbb..c1ce2c556 100644 --- a/tests/opnfv/test_cases/opnfv_yardstick_tc071.yaml +++ b/tests/opnfv/test_cases/opnfv_yardstick_tc071.yaml @@ -95,7 +95,7 @@ context: networks: test: cidr: '10.0.1.0/24' - {% if provider == "vlan" %} + {% if provider == "vlan" or provider == "sriov" %} provider: {{provider}} physical_network: {{physical_network}} {% if segmentation_id %} diff --git a/tests/opnfv/test_cases/opnfv_yardstick_tc072.yaml b/tests/opnfv/test_cases/opnfv_yardstick_tc072.yaml index 09930d442..d237fa92a 100644 --- a/tests/opnfv/test_cases/opnfv_yardstick_tc072.yaml +++ b/tests/opnfv/test_cases/opnfv_yardstick_tc072.yaml @@ -97,7 +97,7 @@ context: networks: test: cidr: '10.0.1.0/24' - {% if provider == "vlan" %} + {% if provider == "vlan" or provider == "sriov" %} provider: {{provider}} physical_network: {{physical_network}} {% if segmentation_id %} diff --git a/tests/opnfv/test_cases/opnfv_yardstick_tc076.yaml b/tests/opnfv/test_cases/opnfv_yardstick_tc076.yaml index 8c0edac83..c5e799c99 100644 --- a/tests/opnfv/test_cases/opnfv_yardstick_tc076.yaml +++ b/tests/opnfv/test_cases/opnfv_yardstick_tc076.yaml @@ -58,7 +58,7 @@ context: networks: test: cidr: '10.0.1.0/24' - {% if provider == "vlan" %} + {% if provider == "vlan" or provider == "sriov" %} provider: {{provider}} physical_network: {{physical_network}} {% if segmentation_id %} diff --git a/tests/opnfv/test_cases/opnfv_yardstick_tc079.yaml b/tests/opnfv/test_cases/opnfv_yardstick_tc079.yaml index 9c15acc9c..04a9225ea 100644 --- a/tests/opnfv/test_cases/opnfv_yardstick_tc079.yaml +++ b/tests/opnfv/test_cases/opnfv_yardstick_tc079.yaml @@ -45,7 +45,7 @@ context: networks: test: cidr: '10.0.1.0/24' - {% if provider == "vlan" %} + {% if provider == "vlan" or provider == "sriov" %} provider: {{provider}} physical_network: {{physical_network}} {% if segmentation_id %} diff --git a/tests/opnfv/test_cases/opnfv_yardstick_tc080.yaml b/tests/opnfv/test_cases/opnfv_yardstick_tc080.yaml index 0da296297..5fe902419 100644 --- a/tests/opnfv/test_cases/opnfv_yardstick_tc080.yaml +++ b/tests/opnfv/test_cases/opnfv_yardstick_tc080.yaml @@ -40,8 +40,12 @@ context: host: image: openretriever/yardstick command: /bin/bash - args: ['-c', 'chmod 700 ~/.ssh; chmod 600 ~/.ssh/*; service ssh restart;while true ; do sleep 10000; done'] + args: ['-c', 'mkdir /root/.ssh; cp /tmp/.ssh/authorized_keys ~/.ssh/.; + chmod 700 ~/.ssh; chmod 600 ~/.ssh/*; service ssh restart; + while true ; do sleep 10000; done'] target: image: openretriever/yardstick command: /bin/bash - args: ['-c', 'chmod 700 ~/.ssh; chmod 600 ~/.ssh/*; service ssh restart;while true ; do sleep 10000; done'] + args: ['-c', 'mkdir /root/.ssh; cp /tmp/.ssh/authorized_keys ~/.ssh/.; + chmod 700 ~/.ssh; chmod 600 ~/.ssh/*; service ssh restart; + while true ; do sleep 10000; done'] diff --git a/tests/opnfv/test_cases/opnfv_yardstick_tc081.yaml b/tests/opnfv/test_cases/opnfv_yardstick_tc081.yaml index fc7eb006c..fc6496bad 100644 --- a/tests/opnfv/test_cases/opnfv_yardstick_tc081.yaml +++ b/tests/opnfv/test_cases/opnfv_yardstick_tc081.yaml @@ -42,7 +42,9 @@ contexts: host: image: openretriever/yardstick command: /bin/bash - args: ['-c', 'chmod 700 ~/.ssh; chmod 600 ~/.ssh/*; service ssh restart;while true ; do sleep 10000; done'] + args: ['-c', 'mkdir /root/.ssh; cp /tmp/.ssh/authorized_keys ~/.ssh/.; + chmod 700 ~/.ssh; chmod 600 ~/.ssh/*; service ssh restart; + while true ; do sleep 10000; done'] - type: Heat name: openstack diff --git a/tests/opnfv/test_cases/opnfv_yardstick_tc082.yaml b/tests/opnfv/test_cases/opnfv_yardstick_tc082.yaml index 4b67f0f20..85b6c91db 100644 --- a/tests/opnfv/test_cases/opnfv_yardstick_tc082.yaml +++ b/tests/opnfv/test_cases/opnfv_yardstick_tc082.yaml @@ -55,7 +55,7 @@ context: networks: test: cidr: "10.0.1.0/24" - {% if provider == "vlan" %} + {% if provider == "vlan" or provider == "sriov" %} provider: {{provider}} physical_network: {{physical_network}} {% if segmentation_id %} diff --git a/tests/opnfv/test_cases/opnfv_yardstick_tc083.yaml b/tests/opnfv/test_cases/opnfv_yardstick_tc083.yaml index 6315fdc07..158f064cd 100755 --- a/tests/opnfv/test_cases/opnfv_yardstick_tc083.yaml +++ b/tests/opnfv/test_cases/opnfv_yardstick_tc083.yaml @@ -81,7 +81,7 @@ context: networks: test: cidr: '10.0.1.0/24' - {% if provider == "vlan" %} + {% if provider == "vlan" or provider == "sriov" %} provider: {{provider}} physical_network: {{physical_network}} {% if segmentation_id %} diff --git a/tests/opnfv/test_cases/opnfv_yardstick_tc084.yaml b/tests/opnfv/test_cases/opnfv_yardstick_tc084.yaml index 472aabe07..9df16578a 100644 --- a/tests/opnfv/test_cases/opnfv_yardstick_tc084.yaml +++ b/tests/opnfv/test_cases/opnfv_yardstick_tc084.yaml @@ -58,7 +58,7 @@ context: networks: test: cidr: '10.0.1.0/24' - {% if provider == "vlan" %} + {% if provider == "vlan" or provider == "sriov" %} provider: {{provider}} physical_network: {{physical_network}} {% if segmentation_id %} diff --git a/tests/opnfv/test_cases/opnfv_yardstick_tc087.yaml b/tests/opnfv/test_cases/opnfv_yardstick_tc087.yaml index d7441836d..13125ade8 100644 --- a/tests/opnfv/test_cases/opnfv_yardstick_tc087.yaml +++ b/tests/opnfv/test_cases/opnfv_yardstick_tc087.yaml @@ -74,7 +74,7 @@ scenarios: type: Duration duration: 1 sla: - action: monitor + action: assert - @@ -172,7 +172,7 @@ scenarios: type: Duration duration: 1 sla: - action: monitor + action: assert - type: "GeneralHA" @@ -239,7 +239,7 @@ scenarios: type: Duration duration: 1 sla: - action: monitor + action: assert contexts: diff --git a/tests/opnfv/test_cases/opnfv_yardstick_tc092.yaml b/tests/opnfv/test_cases/opnfv_yardstick_tc092.yaml index 85ec510df..f2996bcc6 100644 --- a/tests/opnfv/test_cases/opnfv_yardstick_tc092.yaml +++ b/tests/opnfv/test_cases/opnfv_yardstick_tc092.yaml @@ -73,7 +73,7 @@ scenarios: type: Duration duration: 1 sla: - action: monitor + action: assert - type: "GeneralHA" @@ -170,7 +170,7 @@ scenarios: type: Duration duration: 1 sla: - action: monitor + action: assert - type: "GeneralHA" @@ -237,7 +237,7 @@ scenarios: type: Duration duration: 1 sla: - action: monitor + action: assert contexts: diff --git a/tests/opnfv/test_cases/opnfv_yardstick_tc093.yaml b/tests/opnfv/test_cases/opnfv_yardstick_tc093.yaml index a034471aa..27e78a451 100644 --- a/tests/opnfv/test_cases/opnfv_yardstick_tc093.yaml +++ b/tests/opnfv/test_cases/opnfv_yardstick_tc093.yaml @@ -75,7 +75,7 @@ scenarios: type: Duration duration: 1 sla: - action: monitor + action: assert - @@ -208,7 +208,7 @@ scenarios: type: Duration duration: 1 sla: - action: monitor + action: assert - type: "GeneralHA" @@ -274,7 +274,7 @@ scenarios: type: Duration duration: 1 sla: - action: monitor + action: assert contexts: diff --git a/tests/opnfv/test_suites/opnfv_os-odl-ovs-noha_daily.yaml b/tests/opnfv/test_suites/opnfv_os-odl-ovs-noha_daily.yaml new file mode 100644 index 000000000..83b370066 --- /dev/null +++ b/tests/opnfv/test_suites/opnfv_os-odl-ovs-noha_daily.yaml @@ -0,0 +1,64 @@ +############################################################################## +# 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 +############################################################################## +--- +# os-odl-ovs-noha daily task suite + +schema: "yardstick:suite:0.1" + +name: "os-odl-ovs-noha" +test_cases_dir: "tests/opnfv/test_cases/" +test_cases: +- + file_name: opnfv_yardstick_tc002.yaml +- + file_name: opnfv_yardstick_tc005.yaml +- + file_name: opnfv_yardstick_tc010.yaml +- + file_name: opnfv_yardstick_tc011.yaml + constraint: + installer: compass,fuel +- + file_name: opnfv_yardstick_tc012.yaml +- + file_name: opnfv_yardstick_tc014.yaml +- + file_name: opnfv_yardstick_tc037.yaml +- + file_name: opnfv_yardstick_tc055.yaml + constraint: + installer: compass + pod: huawei-pod1 + task_args: + huawei-pod1: '{"file": "etc/yardstick/nodes/compass_sclab_physical/pod.yaml", + "host": "node5"}' +- + file_name: opnfv_yardstick_tc063.yaml + constraint: + installer: compass + pod: huawei-pod1 + task_args: + huawei-pod1: '{"file": "etc/yardstick/nodes/compass_sclab_physical/pod.yaml", + "host": "node5"}' +- + file_name: opnfv_yardstick_tc069.yaml +- + file_name: opnfv_yardstick_tc070.yaml +- + file_name: opnfv_yardstick_tc071.yaml +- + file_name: opnfv_yardstick_tc072.yaml +- + file_name: opnfv_yardstick_tc075.yaml + constraint: + installer: compass + pod: huawei-pod1 + task_args: + huawei-pod1: '{"file": "etc/yardstick/nodes/compass_sclab_physical/pod.yaml", + "host": "node1"}' diff --git a/tests/unit/network_services/vnf_generic/vnf/acl_1rule.yaml b/tests/unit/network_services/vnf_generic/vnf/acl_1rule.yaml deleted file mode 100644 index b184a29e2..000000000 --- a/tests/unit/network_services/vnf_generic/vnf/acl_1rule.yaml +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright (c) 2016-2017 Intel Corporation -# -# 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. - -access-list1: - acl: - access-list-entries: - - ace: - ace-oper-data: - match-counter: 0 - actions: drop,count - matches: - destination-ipv4-network: 152.16.40.20/24 - destination-port-range: - lower-port: 0 - upper-port: 65535 - source-ipv4-network: 0.0.0.0/0 - source-port-range: - lower-port: 0 - upper-port: 65535 - rule-name: rule1588 - - ace: - ace-oper-data: - match-counter: 0 - actions: drop,count - matches: - destination-ipv4-network: 0.0.0.0/0 - destination-port-range: - lower-port: 0 - upper-port: 65535 - source-ipv4-network: 152.16.100.20/24 - source-port-range: - lower-port: 0 - upper-port: 65535 - rule-name: rule1589 - acl-name: sample-ipv4-acl - acl-type: ipv4-acl diff --git a/tests/unit/network_services/vnf_generic/vnf/test_tg_ixload.py b/tests/unit/network_services/vnf_generic/vnf/test_tg_ixload.py deleted file mode 100644 index d831ddd3d..000000000 --- a/tests/unit/network_services/vnf_generic/vnf/test_tg_ixload.py +++ /dev/null @@ -1,318 +0,0 @@ -# Copyright (c) 2016-2017 Intel Corporation -# -# 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. -# - -import subprocess - -import mock -import unittest -import six - -from tests.unit import STL_MOCKS -from yardstick import ssh -from yardstick.common import utils - - -STLClient = mock.MagicMock() -stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) -stl_patch.start() - -if stl_patch: - from yardstick.network_services.vnf_generic.vnf.tg_ixload import IxLoadTrafficGen - from yardstick.network_services.vnf_generic.vnf.tg_ixload import IxLoadResourceHelper - from yardstick.network_services.traffic_profile.base import TrafficProfile - - -NAME = "tg__1" - - -class TestIxLoadTrafficGen(unittest.TestCase): - VNFD = {'vnfd:vnfd-catalog': - {'vnfd': - [{'short-name': 'VpeVnf', - 'vdu': - [{'routing_table': - [{'network': '152.16.100.20', - 'netmask': '255.255.255.0', - 'gateway': '152.16.100.20', - 'if': 'xe0'}, - {'network': '152.16.40.20', - 'netmask': '255.255.255.0', - 'gateway': '152.16.40.20', - 'if': 'xe1'}], - 'description': 'VPE approximation using DPDK', - 'name': 'vpevnf-baremetal', - 'nd_route_tbl': - [{'network': '0064:ff9b:0:0:0:0:9810:6414', - 'netmask': '112', - 'gateway': '0064:ff9b:0:0:0:0:9810:6414', - 'if': 'xe0'}, - {'network': '0064:ff9b:0:0:0:0:9810:2814', - 'netmask': '112', - 'gateway': '0064:ff9b:0:0:0:0:9810:2814', - 'if': 'xe1'}], - 'id': 'vpevnf-baremetal', - 'external-interface': - [{'virtual-interface': - {'dst_mac': '00:00:00:00:00:04', - 'vpci': '0000:05:00.0', - 'local_ip': '152.16.100.19', - 'type': 'PCI-PASSTHROUGH', - 'netmask': '255.255.255.0', - 'dpdk_port_num': 0, - 'bandwidth': '10 Gbps', - 'driver': "i40e", - 'dst_ip': '152.16.100.20', - 'local_iface_name': 'xe0', - 'local_mac': '00:00:00:00:00:02'}, - 'vnfd-connection-point-ref': 'xe0', - 'name': 'xe0'}, - {'virtual-interface': - {'dst_mac': '00:00:00:00:00:03', - 'vpci': '0000:05:00.1', - 'local_ip': '152.16.40.19', - 'type': 'PCI-PASSTHROUGH', - 'driver': "i40e", - 'netmask': '255.255.255.0', - 'dpdk_port_num': 1, - 'bandwidth': '10 Gbps', - 'dst_ip': '152.16.40.20', - 'local_iface_name': 'xe1', - 'local_mac': '00:00:00:00:00:01'}, - 'vnfd-connection-point-ref': 'xe1', - 'name': 'xe1'}]}], - 'description': 'Vpe approximation using DPDK', - 'mgmt-interface': - {'vdu-id': 'vpevnf-baremetal', - 'host': '1.1.1.1', - 'password': 'r00t', - 'user': 'root', - 'ip': '1.1.1.1'}, - 'benchmark': - {'kpi': ['packets_in', 'packets_fwd', 'packets_dropped']}, - 'connection-point': [{'type': 'VPORT', 'name': 'xe0'}, - {'type': 'VPORT', 'name': 'xe1'}], - 'id': 'VpeApproxVnf', 'name': 'VPEVnfSsh'}]}} - - TRAFFIC_PROFILE = { - "schema": "isb:traffic_profile:0.1", - "name": "fixed", - "description": "Fixed traffic profile to run UDP traffic", - "traffic_profile": { - "traffic_type": "FixedTraffic", - "frame_rate": 100, # pps - "flow_number": 10, - "frame_size": 64}} - - def test___init__(self): - with mock.patch("yardstick.ssh.SSH") as ssh: - ssh_mock = mock.Mock(autospec=ssh.SSH) - ssh_mock.execute = \ - mock.Mock(return_value=(0, "", "")) - ssh.from_node.return_value = ssh_mock - vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - ixload_traffic_gen = IxLoadTrafficGen(NAME, vnfd) - self.assertIsNone(ixload_traffic_gen.resource_helper.data) - - def test_collect_kpi(self): - with mock.patch("yardstick.ssh.SSH") as ssh: - ssh_mock = mock.Mock(autospec=ssh.SSH) - ssh_mock.execute = \ - mock.Mock(return_value=(0, "", "")) - ssh.from_node.return_value = ssh_mock - vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - ixload_traffic_gen = IxLoadTrafficGen(NAME, vnfd) - ixload_traffic_gen.data = {} - restult = ixload_traffic_gen.collect_kpi() - self.assertEqual({}, restult) - - def test_listen_traffic(self): - with mock.patch("yardstick.ssh.SSH") as ssh: - ssh_mock = mock.Mock(autospec=ssh.SSH) - ssh_mock.execute = \ - mock.Mock(return_value=(0, "", "")) - ssh.from_node.return_value = ssh_mock - vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - ixload_traffic_gen = IxLoadTrafficGen(NAME, vnfd) - self.assertIsNone(ixload_traffic_gen.listen_traffic({})) - - @mock.patch.object(utils, 'find_relative_file') - @mock.patch.object(utils, 'makedirs') - @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.call") - @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.shutil") - def test_instantiate(self, shutil, *args): - with mock.patch("yardstick.ssh.SSH") as ssh: - ssh_mock = mock.Mock(autospec=ssh.SSH) - ssh_mock.execute = \ - mock.Mock(return_value=(0, "", "")) - ssh_mock.run = \ - mock.Mock(return_value=(0, "", "")) - ssh.from_node.return_value = ssh_mock - vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - ixload_traffic_gen = IxLoadTrafficGen(NAME, vnfd) - scenario_cfg = {'tc': "nsb_test_case", - 'ixia_profile': "ixload.cfg", - 'task_path': "/path/to/task"} - ixload_traffic_gen.RESULTS_MOUNT = "/tmp/result" - shutil.copy = mock.Mock() - scenario_cfg.update({'options': {'packetsize': 64, 'traffic_type': 4, - 'rfc2544': {'allowed_drop_rate': '0.8 - 1'}, - 'vnf__1': {'rules': 'acl_1rule.yaml', - 'vnf_config': {'lb_config': 'SW', - 'lb_count': 1, - 'worker_config': - '1C/1T', - 'worker_threads': 1}} - }}) - with mock.patch.object(six.moves.builtins, 'open', - create=True) as mock_open: - mock_open.return_value = mock.MagicMock() - ixload_traffic_gen.instantiate(scenario_cfg, {}) - - @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.call") - @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.open") - @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.min") - @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.max") - @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.len") - @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.shutil") - def test_run_traffic(self, shutil, *args): - mock_traffic_profile = mock.Mock(autospec=TrafficProfile) - mock_traffic_profile.get_traffic_definition.return_value = "64" - mock_traffic_profile.params = self.TRAFFIC_PROFILE - with mock.patch("yardstick.ssh.SSH") as ssh: - ssh_mock = mock.Mock(autospec=ssh.SSH) - ssh_mock.execute = \ - mock.Mock(return_value=(0, "", "")) - ssh_mock.run = \ - mock.Mock(return_value=(0, "", "")) - ssh.from_node.return_value = ssh_mock - vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - vnfd["mgmt-interface"].update({"tg-config": {}}) - vnfd["mgmt-interface"]["tg-config"].update({"ixchassis": - "1.1.1.1"}) - vnfd["mgmt-interface"]["tg-config"].update({"py_bin_path": - "/root"}) - sut = IxLoadTrafficGen(NAME, vnfd) - sut.connection = mock.Mock() - sut.connection.run = mock.Mock() - sut._traffic_runner = mock.Mock(return_value=0) - shutil.copy = mock.Mock() - result = sut.run_traffic(mock_traffic_profile) - self.assertIsNone(result) - - @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.call") - @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.open") - @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.min") - @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.max") - @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.len") - @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.shutil") - def test_run_traffic_csv(self, shutil, *args): - mock_traffic_profile = mock.Mock(autospec=TrafficProfile) - mock_traffic_profile.get_traffic_definition.return_value = "64" - mock_traffic_profile.params = self.TRAFFIC_PROFILE - with mock.patch("yardstick.ssh.SSH") as ssh: - ssh_mock = mock.Mock(autospec=ssh.SSH) - ssh_mock.execute = \ - mock.Mock(return_value=(0, "", "")) - ssh_mock.run = \ - mock.Mock(return_value=(0, "", "")) - ssh.from_node.return_value = ssh_mock - vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - vnfd["mgmt-interface"].update({"tg-config": {}}) - vnfd["mgmt-interface"]["tg-config"].update({"ixchassis": - "1.1.1.1"}) - vnfd["mgmt-interface"]["tg-config"].update({"py_bin_path": - "/root"}) - sut = IxLoadTrafficGen(NAME, vnfd) - sut.connection = mock.Mock() - sut.connection.run = mock.Mock() - sut._traffic_runner = mock.Mock(return_value=0) - shutil.copy = mock.Mock() - subprocess.call(["touch", "/tmp/1.csv"]) - sut.rel_bin_path = mock.Mock(return_value="/tmp/*.csv") - result = sut.run_traffic(mock_traffic_profile) - self.assertIsNone(result) - - @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.call") - @mock.patch.object(ssh, 'SSH') - def test_terminate(self, *args): - vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - ixload_traffic_gen = IxLoadTrafficGen(NAME, vnfd) - self.assertIsNone(ixload_traffic_gen.terminate()) - - @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.call") - @mock.patch.object(ssh, 'SSH') - def test_parse_csv_read(self, mock_ssh, *args): - vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - kpi_data = { - 'HTTP Total Throughput (Kbps)': 1, - 'HTTP Simulated Users': 2, - 'HTTP Concurrent Connections': '3', - 'HTTP Connection Rate': 4.3, - 'HTTP Transaction Rate': True, - } - http_reader = [kpi_data] - - mock_ssh_type = mock.Mock(autospec=mock_ssh.SSH) - mock_ssh_type.execute.return_value = 0, "", "" - mock_ssh.from_node.return_value = mock_ssh_type - - ixload_traffic_gen = IxLoadTrafficGen(NAME, vnfd) - result = ixload_traffic_gen.resource_helper.result - - ixload_traffic_gen.resource_helper.parse_csv_read(http_reader) - for key_left, key_right in IxLoadResourceHelper.KPI_LIST.items(): - self.assertEqual(result[key_left][-1], int(kpi_data[key_right])) - - @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.call") - @mock.patch.object(ssh, 'SSH') - def test_parse_csv_read_value_error(self, mock_ssh, *args): - vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - http_reader = [{ - 'HTTP Total Throughput (Kbps)': 1, - 'HTTP Simulated Users': 2, - 'HTTP Concurrent Connections': "not a number", - 'HTTP Connection Rate': 4, - 'HTTP Transaction Rate': 5, - }] - - mock_ssh_type = mock.Mock(autospec=mock_ssh.SSH) - mock_ssh_type.execute.return_value = 0, "", "" - mock_ssh.from_node.return_value = mock_ssh_type - - ixload_traffic_gen = IxLoadTrafficGen(NAME, vnfd) - init_value = ixload_traffic_gen.resource_helper.result - - ixload_traffic_gen.resource_helper.parse_csv_read(http_reader) - self.assertDictEqual(ixload_traffic_gen.resource_helper.result, init_value) - - @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.call") - @mock.patch.object(ssh, 'SSH') - def test_parse_csv_read_error(self, mock_ssh, *args): - vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - http_reader = [{ - 'HTTP Total Throughput (Kbps)': 1, - 'HTTP Simulated Users': 2, - 'HTTP Concurrent Connections': 3, - 'HTTP Transaction Rate': 5, - }] - - mock_ssh_type = mock.Mock(autospec=mock_ssh.SSH) - mock_ssh_type.execute.return_value = 0, "", "" - mock_ssh.from_node.return_value = mock_ssh_type - - ixload_traffic_gen = IxLoadTrafficGen(NAME, vnfd) - - with self.assertRaises(KeyError): - ixload_traffic_gen.resource_helper.parse_csv_read(http_reader) diff --git a/tools/cover.sh b/tools/cover.sh index c6e928d1a..4e54a64b7 100644 --- a/tools/cover.sh +++ b/tools/cover.sh @@ -44,14 +44,12 @@ run_coverage_test() { baseline_report=$(mktemp -t yardstick_coverageXXXXXXX) find . -type f -name "*.pyc" -delete + coverage erase - # Temporarily run tests from two directories, until all tests have moved - coverage run -p -m unittest discover ./tests/unit coverage run -p -m unittest discover ./yardstick/tests/unit coverage combine - # Temporarily omit yardstick/tests from the report - coverage report --omit=yardstick/tests/*/* > ${baseline_report} + coverage report > ${baseline_report} coverage erase # debug awk @@ -72,13 +70,10 @@ run_coverage_test() { find . -type f -name "*.pyc" -delete - # Temporarily run tests from two directories, until all tests have moved - coverage run -p -m unittest discover ./tests/unit coverage run -p -m unittest discover ./yardstick/tests/unit coverage combine - # Temporarily omit yardstick/tests from the report - coverage report --omit=yardstick/tests/*/* > ${current_report} + coverage report > ${current_report} coverage erase rm -rf cover-$PY_VER diff --git a/tools/run_tests.sh b/tools/run_tests.sh index 32c4f19e4..49f628eec 100755 --- a/tools/run_tests.sh +++ b/tools/run_tests.sh @@ -28,17 +28,8 @@ run_tests() { echo "Running unittest ... " if [ $FILE_OPTION == "f" ]; then - python -m unittest discover -v -s tests/unit > $logfile 2>&1 - if [ $? -ne 0 ]; then - echo "FAILED, results in $logfile" - exit 1 - fi - python -m unittest discover -v -s yardstick/tests/unit >> $logfile 2>&1 + python -m unittest discover -v -s yardstick/tests/unit > $logfile 2>&1 else - python -m unittest discover -v -s tests/unit - if [ $? -ne 0 ]; then - exit 1 - fi python -m unittest discover -v -s yardstick/tests/unit fi diff --git a/yardstick/benchmark/contexts/__init__.py b/yardstick/benchmark/contexts/__init__.py index e69de29bb..d50f08cc3 100644 --- a/yardstick/benchmark/contexts/__init__.py +++ b/yardstick/benchmark/contexts/__init__.py @@ -0,0 +1,20 @@ +# Copyright (c) 2016-2017 Intel Corporation +# +# 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. + +CONTEXT_DUMMY = "Dummy" +CONTEXT_HEAT = "Heat" +CONTEXT_KUBERNETES = "Kubernetes" +CONTEXT_NODE = "Node" +CONTEXT_STANDALONEOVSDPDK = "StandaloneOvsDpdk" +CONTEXT_STANDALONESRIOV = "StandaloneSriov" diff --git a/yardstick/benchmark/contexts/base.py b/yardstick/benchmark/contexts/base.py index 692c16892..f3f5879eb 100644 --- a/yardstick/benchmark/contexts/base.py +++ b/yardstick/benchmark/contexts/base.py @@ -8,10 +8,14 @@ ############################################################################## import abc +import errno import six +import os from yardstick.common import constants from yardstick.common import utils +from yardstick.common import yaml_loader +from yardstick.common.constants import YARDSTICK_ROOT_PATH class Flags(object): @@ -45,20 +49,13 @@ class Context(object): list = [] SHORT_TASK_ID_LEN = 8 - @staticmethod - def split_name(name, sep='.'): - try: - name_iter = iter(name.split(sep)) - except AttributeError: - # name is not a string - return None, None - return next(name_iter), next(name_iter, None) - - def __init__(self): + def __init__(self, host_name_separator='.'): Context.list.append(self) self._flags = Flags() self._name = None self._task_id = None + self.file_path = None + self._host_name_separator = host_name_separator def init(self, attrs): """Initiate context""" @@ -68,6 +65,35 @@ class Context(object): self._name_task_id = '{}-{}'.format( self._name, self._task_id[:self.SHORT_TASK_ID_LEN]) + def split_host_name(self, name): + if (isinstance(name, six.string_types) + and self._host_name_separator in name): + return tuple(name.split(self._host_name_separator, 1)) + return None, None + + def read_pod_file(self, attrs): + self.file_path = file_path = attrs.get("file", "pod.yaml") + try: + cfg = yaml_loader.read_yaml_file(self.file_path) + except IOError as io_error: + if io_error.errno != errno.ENOENT: + raise + + self.file_path = os.path.join(YARDSTICK_ROOT_PATH, file_path) + cfg = yaml_loader.read_yaml_file(self.file_path) + + for node in cfg["nodes"]: + node["ctx_type"] = self.__context_type__ + + self.nodes.extend(cfg["nodes"]) + self.controllers.extend([node for node in cfg["nodes"] + if node.get("role") == "Controller"]) + self.computes.extend([node for node in cfg["nodes"] + if node.get("role") == "Compute"]) + self.baremetals.extend([node for node in cfg["nodes"] + if node.get("role") == "Baremetal"]) + return cfg + @property def name(self): if self._flags.no_setup or self._flags.no_teardown: @@ -79,6 +105,10 @@ class Context(object): def assigned_name(self): return self._name + @property + def host_name_separator(self): + return self._host_name_separator + @staticmethod def get_cls(context_type): """Return class of specified type.""" @@ -129,6 +159,25 @@ class Context(object): attr_name) @staticmethod + def get_physical_nodes(): + """return physical node names for all contexts""" + physical_nodes = {} + for context in Context.list: + nodes = context._get_physical_nodes() + physical_nodes.update({context._name: nodes}) + + return physical_nodes + + @staticmethod + def get_physical_node_from_server(server_name): + """return physical nodes for all contexts""" + context = Context.get_context_from_server(server_name) + if context == None: + return None + + return context._get_physical_node_for_server(server_name) + + @staticmethod def get_context_from_server(attr_name): """lookup context info by name from node config attr_name: either a name of the node created by yardstick or a dict @@ -157,3 +206,15 @@ class Context(object): except StopIteration: raise ValueError("context not found for server %r" % attr_name) + + @abc.abstractmethod + def _get_physical_nodes(self): + """return the list of physical nodes in context""" + + @abc.abstractmethod + def _get_physical_node_for_server(self, server_name): + """ Find physical node for given server + + :param server_name: (string) Server name in scenario + :return string: <node_name>.<context_name> + """ diff --git a/yardstick/benchmark/contexts/dummy.py b/yardstick/benchmark/contexts/dummy.py index a9e4564fe..9faca4c63 100644 --- a/yardstick/benchmark/contexts/dummy.py +++ b/yardstick/benchmark/contexts/dummy.py @@ -7,17 +7,18 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -from yardstick.benchmark.contexts.base import Context +from yardstick.benchmark import contexts +from yardstick.benchmark.contexts import base -class DummyContext(Context): +class DummyContext(base.Context): """Class that handle dummy info. This class is also used to test the abstract class Context because it provides a minimal concrete implementation of a subclass. """ - __context_type__ = "Dummy" + __context_type__ = contexts.CONTEXT_DUMMY def deploy(self): """Don't need to deploy""" @@ -32,3 +33,9 @@ class DummyContext(Context): def _get_network(self, attr_name): return None + + def _get_physical_nodes(self): + return None + + def _get_physical_node_for_server(self, server_name): + return None diff --git a/yardstick/benchmark/contexts/heat.py b/yardstick/benchmark/contexts/heat.py index 82861829e..f118ffc32 100644 --- a/yardstick/benchmark/contexts/heat.py +++ b/yardstick/benchmark/contexts/heat.py @@ -16,6 +16,7 @@ from collections import OrderedDict import ipaddress import pkg_resources +from yardstick.benchmark import contexts from yardstick.benchmark.contexts.base import Context from yardstick.benchmark.contexts.model import Network from yardstick.benchmark.contexts.model import PlacementGroup, ServerGroup @@ -29,6 +30,7 @@ from yardstick.common import constants as consts from yardstick.common import utils from yardstick.common.utils import source_env from yardstick.ssh import SSH +from yardstick.common import openstack_utils LOG = logging.getLogger(__name__) @@ -46,7 +48,7 @@ def h_join(*args): class HeatContext(Context): """Class that represents a context in the logical model""" - __context_type__ = "Heat" + __context_type__ = contexts.CONTEXT_HEAT def __init__(self): self.stack = None @@ -68,6 +70,12 @@ class HeatContext(Context): self.shade_client = None self.heat_timeout = None self.key_filename = None + self.shade_client = None + self.operator_client = None + self.nodes = [] + self.controllers = [] + self.computes = [] + self.baremetals = [] super(HeatContext, self).__init__() @staticmethod @@ -96,6 +104,14 @@ class HeatContext(Context): self.template_file = attrs.get("heat_template") + self.shade_client = openstack_utils.get_shade_client() + self.operator_client = openstack_utils.get_shade_operator_client() + + try: + self.read_pod_file(attrs) + except IOError: + LOG.warning("No pod file specified. NVFi metrics will be disabled") + self.heat_timeout = attrs.get("timeout", DEFAULT_HEAT_TIMEOUT) if self.template_file: self.heat_parameters = attrs.get("heat_parameters") @@ -465,7 +481,7 @@ class HeatContext(Context): with attribute name mapping when using external heat templates """ if isinstance(attr_name, collections.Mapping): - node_name, cname = self.split_name(attr_name['name']) + node_name, cname = self.split_host_name(attr_name['name']) if cname is None or cname != self.name: return None @@ -528,3 +544,30 @@ class HeatContext(Context): "physical_network": network.physical_network, } return result + + def _get_physical_nodes(self): + return self.nodes + + def _get_physical_node_for_server(self, server_name): + node_name, ctx_name = self.split_host_name(server_name) + if ctx_name is None or self.name != ctx_name: + return None + + matching_nodes = [s for s in self.servers if s.name == node_name] + if len(matching_nodes) == 0: + return None + + server = openstack_utils.get_server(self.shade_client, + name_or_id=server_name) + + if server: + server = server.toDict() + list_hypervisors = self.operator_client.list_hypervisors() + + for hypervisor in list_hypervisors: + if hypervisor.hypervisor_hostname == server['OS-EXT-SRV-ATTR:hypervisor_hostname']: + for node in self.nodes: + if node['ip'] == hypervisor.host_ip: + return "{}.{}".format(node['name'], self._name) + + return None diff --git a/yardstick/benchmark/contexts/kubernetes.py b/yardstick/benchmark/contexts/kubernetes.py index 4bea991ea..e1553c72b 100644 --- a/yardstick/benchmark/contexts/kubernetes.py +++ b/yardstick/benchmark/contexts/kubernetes.py @@ -7,50 +7,57 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -from __future__ import absolute_import +import collections import logging -import time import pkg_resources +import time import paramiko -from yardstick.benchmark.contexts.base import Context -from yardstick.orchestrator.kubernetes import KubernetesTemplate +from yardstick.benchmark import contexts +from yardstick.benchmark.contexts import base as ctx_base +from yardstick.benchmark.contexts import model +from yardstick.common import constants +from yardstick.common import exceptions from yardstick.common import kubernetes_utils as k8s_utils from yardstick.common import utils +from yardstick.orchestrator import kubernetes + LOG = logging.getLogger(__name__) BITS_LENGTH = 2048 -class KubernetesContext(Context): +class KubernetesContext(ctx_base.Context): """Class that handle nodes info""" - __context_type__ = "Kubernetes" + __context_type__ = contexts.CONTEXT_KUBERNETES def __init__(self): self.ssh_key = '' self.key_path = '' self.public_key_path = '' self.template = None - - super(KubernetesContext, self).__init__() + super(KubernetesContext, self).__init__(host_name_separator='-') def init(self, attrs): super(KubernetesContext, self).init(attrs) - template_cfg = attrs.get('servers', {}) - self.template = KubernetesTemplate(self.name, template_cfg) - + networks = attrs.get('networks', {}) + self.template = kubernetes.KubernetesTemplate(self.name, attrs) self.ssh_key = '{}-key'.format(self.name) - self.key_path = self._get_key_path() self.public_key_path = '{}.pub'.format(self.key_path) + self._networks = collections.OrderedDict( + (net_name, model.Network(net_name, self, network)) + for net_name, network in networks.items()) def deploy(self): LOG.info('Creating ssh key') self._set_ssh_key() + self._create_crd() + self._create_networks() LOG.info('Launch containers') self._create_rcs() self._create_services() @@ -64,6 +71,8 @@ class KubernetesContext(Context): self._delete_rcs() self._delete_pods() self._delete_services() + self._delete_networks() + self._delete_crd() super(KubernetesContext, self).undeploy() @@ -90,7 +99,7 @@ class KubernetesContext(Context): obj.delete() def _create_rcs(self): - for obj in self.template.k8s_objs: + for obj in self.template.rc_objs: self._create_rc(obj.get_template()) def _create_rc(self, template): @@ -101,14 +110,34 @@ class KubernetesContext(Context): self._delete_rc(rc) def _delete_rc(self, rc): - k8s_utils.delete_replication_controller(rc) + k8s_utils.delete_replication_controller(rc, skip_codes=[404]) def _delete_pods(self): for pod in self.template.pods: self._delete_pod(pod) def _delete_pod(self, pod): - k8s_utils.delete_pod(pod) + k8s_utils.delete_pod(pod, skip_codes=[404]) + + def _create_crd(self): + LOG.info('Create Custom Resource Definition elements') + for crd in self.template.crd: + crd.create() + + def _delete_crd(self): + LOG.info('Delete Custom Resource Definition elements') + for crd in self.template.crd: + crd.delete() + + def _create_networks(self): # pragma: no cover + LOG.info('Create Network elements') + for net in self.template.network_objs: + net.create() + + def _delete_networks(self): # pragma: no cover + LOG.info('Create Network elements') + for net in self.template.network_objs: + net.delete() def _get_key_path(self): task_id = self.name.split('-')[-1] @@ -130,27 +159,76 @@ class KubernetesContext(Context): k8s_utils.create_config_map(self.ssh_key, {'authorized_keys': key}) def _delete_ssh_key(self): - k8s_utils.delete_config_map(self.ssh_key) + k8s_utils.delete_config_map(self.ssh_key, skip_codes=[404]) utils.remove_file(self.key_path) utils.remove_file(self.public_key_path) def _get_server(self, name): - service_name = '{}-service'.format(name) - service = k8s_utils.get_service_by_name(service_name).ports[0] - - host = { - 'name': service.name, + node_ports = self._get_service_ports(name) + for sn_port in (sn_port for sn_port in node_ports + if sn_port['port'] == constants.SSH_PORT): + node_port = sn_port['node_port'] + break + else: + raise exceptions.KubernetesSSHPortNotDefined() + + return { + 'name': name, 'ip': self._get_node_ip(), 'private_ip': k8s_utils.get_pod_by_name(name).status.pod_ip, - 'ssh_port': service.node_port, + 'ssh_port': node_port, 'user': 'root', 'key_filename': self.key_path, + 'interfaces': self._get_interfaces(name), + 'service_ports': node_ports } - return host + def _get_network(self, net_name): + """Retrieves the network object, searching by name + + :param net_name: (str) replication controller name + :return: (dict) network information (name) + """ + network = self._networks.get(net_name) + if not network: + return + return {'name': net_name} + + def _get_interfaces(self, rc_name): + """Retrieves the network list of a replication controller + + :param rc_name: (str) replication controller name + :return: (dict) names and information of the networks used in this + replication controller; those networks must be defined in the + Kubernetes cluster + """ + rc = self.template.get_rc_by_name(rc_name) + if not rc: + return {} + return {name: {'network_name': name, + 'local_mac': None, + 'local_ip': None} + for name in rc.networks} def _get_node_ip(self): return k8s_utils.get_node_list().items[0].status.addresses[0].address - def _get_network(self, attr_name): + def _get_physical_nodes(self): return None + + def _get_physical_node_for_server(self, server_name): + return None + + def _get_service_ports(self, name): + service_name = '{}-service'.format(name) + service = k8s_utils.get_service_by_name(service_name) + if not service: + raise exceptions.KubernetesServiceObjectNotDefined() + ports = [] + for port in service.ports: + ports.append({'name': port.name, + 'node_port': port.node_port, + 'port': port.port, + 'protocol': port.protocol, + 'target_port': port.target_port}) + return ports diff --git a/yardstick/benchmark/contexts/node.py b/yardstick/benchmark/contexts/node.py index fa619a9aa..d233e02ae 100644 --- a/yardstick/benchmark/contexts/node.py +++ b/yardstick/benchmark/contexts/node.py @@ -7,8 +7,6 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -from __future__ import absolute_import -import errno import subprocess import os import collections @@ -19,10 +17,11 @@ import six import pkg_resources from yardstick import ssh +from yardstick.benchmark import contexts from yardstick.benchmark.contexts.base import Context from yardstick.common.constants import ANSIBLE_DIR, YARDSTICK_ROOT_PATH from yardstick.common.ansible_common import AnsibleCommon -from yardstick.common.yaml_loader import yaml_load +from yardstick.common.exceptions import ContextUpdateCollectdForNodeError LOG = logging.getLogger(__name__) @@ -32,7 +31,7 @@ DEFAULT_DISPATCH = 'script' class NodeContext(Context): """Class that handle nodes info""" - __context_type__ = "Node" + __context_type__ = contexts.CONTEXT_NODE def __init__(self): self.file_path = None @@ -49,40 +48,11 @@ class NodeContext(Context): } super(NodeContext, self).__init__() - def read_config_file(self): - """Read from config file""" - - with open(self.file_path) as stream: - LOG.info("Parsing pod file: %s", self.file_path) - cfg = yaml_load(stream) - return cfg - def init(self, attrs): """initializes itself from the supplied arguments""" super(NodeContext, self).init(attrs) - self.file_path = file_path = attrs.get("file", "pod.yaml") - - try: - cfg = self.read_config_file() - except IOError as io_error: - if io_error.errno != errno.ENOENT: - raise - - self.file_path = os.path.join(YARDSTICK_ROOT_PATH, file_path) - cfg = self.read_config_file() - - self.nodes.extend(cfg["nodes"]) - self.controllers.extend([node for node in cfg["nodes"] - if node.get("role") == "Controller"]) - self.computes.extend([node for node in cfg["nodes"] - if node.get("role") == "Compute"]) - self.baremetals.extend([node for node in cfg["nodes"] - if node.get("role") == "Baremetal"]) - LOG.debug("Nodes: %r", self.nodes) - LOG.debug("Controllers: %r", self.controllers) - LOG.debug("Computes: %r", self.computes) - LOG.debug("BareMetals: %r", self.baremetals) + cfg = self.read_pod_file(attrs) self.env = attrs.get('env', {}) self.attrs = attrs @@ -135,11 +105,37 @@ class NodeContext(Context): playbook = os.path.join(ANSIBLE_DIR, playbook) return playbook + def _get_physical_nodes(self): + return self.nodes + + def _get_physical_node_for_server(self, server_name): + + node_name, context_name = self.split_host_name(server_name) + + if context_name is None or self.name != context_name: + return None + + for n in (n for n in self.nodes if n["name"] == node_name): + return "{}.{}".format(n["name"], self._name) + + return None + + def update_collectd_options_for_node(self, options, attr_name): + node_name, _ = self.split_host_name(attr_name) + + matching_nodes = (n for n in self.nodes if n["name"] == node_name) + try: + node = next(matching_nodes) + except StopIteration: + raise ContextUpdateCollectdForNodeError(attr_name=attr_name) + + node["collectd"] = options + def _get_server(self, attr_name): """lookup server info by name from context attr_name: a name for a server listed in nodes config file """ - node_name, name = self.split_name(attr_name) + node_name, name = self.split_host_name(attr_name) if name is None or self.name != name: return None diff --git a/yardstick/benchmark/contexts/standalone/model.py b/yardstick/benchmark/contexts/standalone/model.py index 4d43f2611..ecddcbbe0 100644 --- a/yardstick/benchmark/contexts/standalone/model.py +++ b/yardstick/benchmark/contexts/standalone/model.py @@ -26,7 +26,7 @@ import xml.etree.ElementTree as ET from yardstick import ssh from yardstick.common import constants from yardstick.common import exceptions -from yardstick.common.yaml_loader import yaml_load +from yardstick.common import yaml_loader from yardstick.network_services.utils import PciAddress from yardstick.network_services.helpers.cpu import CpuSysCores @@ -45,7 +45,7 @@ VM_TEMPLATE = """ <vcpu cpuset='{cpuset}'>{vcpu}</vcpu> {cputune} <os> - <type arch="x86_64" machine="pc-i440fx-utopic">hvm</type> + <type arch="x86_64" machine="pc-i440fx-xenial">hvm</type> <boot dev="hd" /> </os> <features> @@ -394,26 +394,18 @@ class StandaloneContextHelper(object): return pf_vfs - def read_config_file(self): - """Read from config file""" - - with open(self.file_path) as stream: - LOG.info("Parsing pod file: %s", self.file_path) - cfg = yaml_load(stream) - return cfg - def parse_pod_file(self, file_path, nfvi_role='Sriov'): self.file_path = file_path nodes = [] nfvi_host = [] try: - cfg = self.read_config_file() + cfg = yaml_loader.read_yaml_file(self.file_path) except IOError as io_error: if io_error.errno != errno.ENOENT: raise self.file_path = os.path.join(constants.YARDSTICK_ROOT_PATH, file_path) - cfg = self.read_config_file() + cfg = yaml_loader.read_yaml_file(self.file_path) nodes.extend([node for node in cfg["nodes"] if str(node["role"]) != nfvi_role]) nfvi_host.extend([node for node in cfg["nodes"] if str(node["role"]) == nfvi_role]) diff --git a/yardstick/benchmark/contexts/standalone/ovs_dpdk.py b/yardstick/benchmark/contexts/standalone/ovs_dpdk.py index b9e66a481..88ad598c3 100644 --- a/yardstick/benchmark/contexts/standalone/ovs_dpdk.py +++ b/yardstick/benchmark/contexts/standalone/ovs_dpdk.py @@ -20,11 +20,12 @@ import re import time from yardstick import ssh -from yardstick.network_services.utils import get_nsb_option -from yardstick.benchmark.contexts.base import Context +from yardstick.benchmark import contexts +from yardstick.benchmark.contexts import base from yardstick.benchmark.contexts.standalone import model from yardstick.common import exceptions from yardstick.network_services import utils +from yardstick.network_services.utils import get_nsb_option LOG = logging.getLogger(__name__) @@ -32,12 +33,12 @@ LOG = logging.getLogger(__name__) MAIN_BRIDGE = 'br0' -class OvsDpdkContext(Context): +class OvsDpdkContext(base.Context): """ This class handles OVS standalone nodes - VM running on Non-Managed NFVi Configuration: ovs_dpdk """ - __context_type__ = "StandaloneOvsDpdk" + __context_type__ = contexts.CONTEXT_STANDALONEOVSDPDK SUPPORTED_OVS_TO_DPDK_MAP = { '2.6.0': '16.07.1', @@ -298,13 +299,28 @@ class OvsDpdkContext(Context): for vm in self.vm_names: model.Libvirt.check_if_vm_exists_and_delete(vm, self.connection) + def _get_physical_nodes(self): + return self.nfvi_host + + def _get_physical_node_for_server(self, server_name): + node_name, ctx_name = self.split_host_name(server_name) + if ctx_name is None or self.name != ctx_name: + return None + + matching_nodes = [s for s in self.servers if s == node_name] + if len(matching_nodes) == 0: + return None + + # self.nfvi_host always contain only one host + return "{}.{}".format(self.nfvi_host[0]["name"], self._name) + def _get_server(self, attr_name): """lookup server info by name from context Keyword arguments: attr_name -- A name for a server listed in nodes config file """ - node_name, name = self.split_name(attr_name) + node_name, name = self.split_host_name(attr_name) if name is None or self.name != name: return None diff --git a/yardstick/benchmark/contexts/standalone/sriov.py b/yardstick/benchmark/contexts/standalone/sriov.py index 95472fdda..3da12a9a8 100644 --- a/yardstick/benchmark/contexts/standalone/sriov.py +++ b/yardstick/benchmark/contexts/standalone/sriov.py @@ -18,20 +18,21 @@ import logging import collections from yardstick import ssh -from yardstick.network_services.utils import get_nsb_option -from yardstick.benchmark.contexts.base import Context +from yardstick.benchmark import contexts +from yardstick.benchmark.contexts import base from yardstick.benchmark.contexts.standalone import model +from yardstick.network_services.utils import get_nsb_option from yardstick.network_services.utils import PciAddress LOG = logging.getLogger(__name__) -class SriovContext(Context): +class SriovContext(base.Context): """ This class handles SRIOV standalone nodes - VM running on Non-Managed NFVi Configuration: sr-iov """ - __context_type__ = "StandaloneSriov" + __context_type__ = contexts.CONTEXT_STANDALONESRIOV def __init__(self): self.file_path = None @@ -106,13 +107,29 @@ class SriovContext(Context): build_vfs = "echo 0 > /sys/bus/pci/devices/{0}/sriov_numvfs" self.connection.execute(build_vfs.format(ports.get('phy_port'))) + def _get_physical_nodes(self): + return self.nfvi_host + + def _get_physical_node_for_server(self, server_name): + + # self.nfvi_host always contain only one host. + node_name, ctx_name = self.split_host_name(server_name) + if ctx_name is None or self.name != ctx_name: + return None + + matching_nodes = [s for s in self.servers if s == node_name] + if len(matching_nodes) == 0: + return None + + return "{}.{}".format(self.nfvi_host[0]["name"], self._name) + def _get_server(self, attr_name): """lookup server info by name from context Keyword arguments: attr_name -- A name for a server listed in nodes config file """ - node_name, name = self.split_name(attr_name) + node_name, name = self.split_host_name(attr_name) if name is None or self.name != name: return None @@ -194,10 +211,10 @@ class SriovContext(Context): slot = index + idx + 10 vf['vpci'] = \ "{}:{}:{:02x}.{}".format(vpci.domain, vpci.bus, slot, vpci.function) - model.Libvirt.add_sriov_interfaces( - vf['vpci'], vf['vf_pci']['vf_pci'], vf['mac'], str(cfg)) self.connection.execute("ifconfig %s up" % vf['interface']) self.connection.execute(vf_spoofchk.format(vf['interface'])) + return model.Libvirt.add_sriov_interfaces( + vf['vpci'], vf['vf_pci']['vf_pci'], vf['mac'], str(cfg)) def setup_sriov_context(self): nodes = [] @@ -220,7 +237,7 @@ class SriovContext(Context): network_ports = collections.OrderedDict( {k: v for k, v in vnf["network_ports"].items() if k != 'mgmt'}) for idx, vfs in enumerate(network_ports.values()): - self._enable_interfaces(index, idx, vfs, cfg) + xml_str = self._enable_interfaces(index, idx, vfs, xml_str) # copy xml to target... model.Libvirt.write_file(cfg, xml_str) diff --git a/yardstick/benchmark/core/task.py b/yardstick/benchmark/core/task.py index 697cc007f..1dfd6c31e 100644 --- a/yardstick/benchmark/core/task.py +++ b/yardstick/benchmark/core/task.py @@ -22,7 +22,8 @@ import collections from six.moves import filter from jinja2 import Environment -from yardstick.benchmark.contexts.base import Context +from yardstick.benchmark import contexts +from yardstick.benchmark.contexts import base as base_context from yardstick.benchmark.runners import base as base_runner from yardstick.common.constants import CONF_FILE from yardstick.common.yaml_loader import yaml_load @@ -359,7 +360,7 @@ class Task(object): # pragma: no cover if is_ip_addr(target): context_cfg['target'] = {"ipaddr": target} else: - context_cfg['target'] = Context.get_server(target) + context_cfg['target'] = base_context.Context.get_server(target) if self._is_same_context(cfg["host"], target): context_cfg['target']["ipaddr"] = context_cfg['target']["private_ip"] else: @@ -367,7 +368,7 @@ class Task(object): # pragma: no cover host_name = server_name.get('host', scenario_cfg.get('host')) if host_name: - context_cfg['host'] = Context.get_server(host_name) + context_cfg['host'] = base_context.Context.get_server(host_name) for item in [server_name, scenario_cfg]: try: @@ -384,7 +385,8 @@ class Task(object): # pragma: no cover ip_list.append(target) context_cfg['target'] = {} else: - context_cfg['target'] = Context.get_server(target) + context_cfg['target'] = ( + base_context.Context.get_server(target)) if self._is_same_context(scenario_cfg["host"], target): ip_list.append(context_cfg["target"]["private_ip"]) @@ -412,7 +414,8 @@ class Task(object): # pragma: no cover with attribute name mapping when using external heat templates """ for context in self.contexts: - if context.__context_type__ not in {"Heat", "Kubernetes"}: + if context.__context_type__ not in {contexts.CONTEXT_HEAT, + contexts.CONTEXT_KUBERNETES}: continue host = context._get_server(host_attr) @@ -553,19 +556,19 @@ class TaskParser(object): # pragma: no cover elif "contexts" in cfg: context_cfgs = cfg["contexts"] else: - context_cfgs = [{"type": "Dummy"}] + context_cfgs = [{"type": contexts.CONTEXT_DUMMY}] - contexts = [] + _contexts = [] for cfg_attrs in context_cfgs: cfg_attrs['task_id'] = task_id # default to Heat context because we are testing OpenStack - context_type = cfg_attrs.get("type", "Heat") - context = Context.get(context_type) + context_type = cfg_attrs.get("type", contexts.CONTEXT_HEAT) + context = base_context.Context.get(context_type) context.init(cfg_attrs) # Update the name in case the context has used the name_suffix cfg_attrs['name'] = context.name - contexts.append(context) + _contexts.append(context) run_in_parallel = cfg.get("run_in_parallel", False) @@ -578,17 +581,17 @@ class TaskParser(object): # pragma: no cover # relative to task path scenario["task_path"] = os.path.dirname(self.path) - self._change_node_names(scenario, contexts) + self._change_node_names(scenario, _contexts) # TODO we need something better here, a class that represent the file return {'scenarios': cfg['scenarios'], 'run_in_parallel': run_in_parallel, 'meet_precondition': meet_precondition, - 'contexts': contexts, + 'contexts': _contexts, 'rendered': rendered} @staticmethod - def _change_node_names(scenario, contexts): + def _change_node_names(scenario, _contexts): """Change the node names in a scenario, depending on the context config The nodes (VMs or physical servers) are referred in the context section @@ -619,27 +622,22 @@ class TaskParser(object): # pragma: no cover nodes: tg__0: tg_0.yardstick vnf__0: vnf_0.yardstick + + NOTE: in Kubernetes context, the separator character between the server + name and the context name is "-": + scenario: + host: host-k8s + target: target-k8s """ def qualified_name(name): - try: - # for openstack - node_name, context_name = name.split('.') - sep = '.' - except ValueError: - # for kubernetes, some kubernetes resources don't support - # name format like 'xxx.xxx', so we use '-' instead - # need unified later - node_name, context_name = name.split('-') - sep = '-' - - try: - ctx = next((context for context in contexts - if context.assigned_name == context_name)) - except StopIteration: - raise y_exc.ScenarioConfigContextNameNotFound( - context_name=context_name) + for context in _contexts: + host_name, ctx_name = context.split_host_name(name) + if context.assigned_name == ctx_name: + return '{}{}{}'.format(host_name, + context.host_name_separator, + context.name) - return '{}{}{}'.format(node_name, sep, ctx.name) + raise y_exc.ScenarioConfigContextNameNotFound(host_name=name) if 'host' in scenario: scenario['host'] = qualified_name(scenario['host']) @@ -723,7 +721,8 @@ def _is_background_scenario(scenario): def parse_nodes_with_context(scenario_cfg): """parse the 'nodes' fields in scenario """ # ensure consistency in node instantiation order - return OrderedDict((nodename, Context.get_server(scenario_cfg["nodes"][nodename])) + return OrderedDict((nodename, base_context.Context.get_server( + scenario_cfg["nodes"][nodename])) for nodename in sorted(scenario_cfg["nodes"])) @@ -739,7 +738,7 @@ def get_networks_from_nodes(nodes): network_name = interface.get('network_name') if not network_name: continue - network = Context.get_network(network_name) + network = base_context.Context.get_network(network_name) if network: networks[network['name']] = network return networks diff --git a/yardstick/benchmark/runners/arithmetic.py b/yardstick/benchmark/runners/arithmetic.py index 6aaaed888..ecb59f960 100755 --- a/yardstick/benchmark/runners/arithmetic.py +++ b/yardstick/benchmark/runners/arithmetic.py @@ -37,6 +37,7 @@ import six from six.moves import range from yardstick.benchmark.runners import base +from yardstick.common import exceptions as y_exc LOG = logging.getLogger(__name__) @@ -86,7 +87,7 @@ def _worker_process(queue, cls, method_name, scenario_cfg, loop_iter = six.moves.zip(*param_iters) else: LOG.warning("iter_type unrecognized: %s", iter_type) - raise TypeError("iter_type unrecognized: %s", iter_type) + raise TypeError("iter_type unrecognized: %s" % iter_type) # Populate options and run the requested method for each value combination for comb_values in loop_iter: @@ -105,14 +106,14 @@ def _worker_process(queue, cls, method_name, scenario_cfg, try: result = method(data) - except AssertionError as assertion: + except y_exc.SLAValidationError as error: # SLA validation failed in scenario, determine what to do now if sla_action == "assert": raise elif sla_action == "monitor": - LOG.warning("SLA validation failed: %s", assertion.args) - errors = assertion.args - except Exception as e: + LOG.warning("SLA validation failed: %s", error.args) + errors = error.args + except Exception as e: # pylint: disable=broad-except errors = traceback.format_exc() LOG.exception(e) else: diff --git a/yardstick/benchmark/runners/base.py b/yardstick/benchmark/runners/base.py index fbdf6c281..af2557441 100755 --- a/yardstick/benchmark/runners/base.py +++ b/yardstick/benchmark/runners/base.py @@ -12,27 +12,26 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. +# +# This is a modified copy of ``rally/rally/benchmark/runners/base.py`` -# yardstick comment: this is a modified copy of -# rally/rally/benchmark/runners/base.py - -from __future__ import absolute_import - +import importlib import logging import multiprocessing import subprocess import time import traceback -from subprocess import CalledProcessError - -import importlib -from six.moves.queue import Empty +from six import moves -import yardstick.common.utils as utils from yardstick.benchmark.scenarios import base as base_scenario +from yardstick.common import messaging +from yardstick.common.messaging import payloads +from yardstick.common.messaging import producer +from yardstick.common import utils from yardstick.dispatcher.base import Base as DispatcherBase + log = logging.getLogger(__name__) @@ -41,7 +40,7 @@ def _execute_shell_command(command): exitcode = 0 try: output = subprocess.check_output(command, shell=True) - except CalledProcessError: + except subprocess.CalledProcessError: exitcode = -1 output = traceback.format_exc() log.error("exec command '%s' error:\n ", command) @@ -245,7 +244,7 @@ class Runner(object): log.debug("output_queue size %s", self.output_queue.qsize()) try: result.update(self.output_queue.get(True, 1)) - except Empty: + except moves.queue.Empty: pass return result @@ -259,7 +258,7 @@ class Runner(object): log.debug("result_queue size %s", self.result_queue.qsize()) try: one_record = self.result_queue.get(True, 1) - except Empty: + except moves.queue.Empty: pass else: if output_in_influxdb: @@ -272,3 +271,22 @@ class Runner(object): dispatchers = DispatcherBase.get(self.config['output_config']) dispatcher = next((d for d in dispatchers if d.__dispatcher_type__ == 'Influxdb')) dispatcher.upload_one_record(record, self.case_name, '', task_id=self.task_id) + + +class RunnerProducer(producer.MessagingProducer): + """Class implementing the message producer for runners""" + + def __init__(self, _id): + super(RunnerProducer, self).__init__(messaging.TOPIC_RUNNER, _id=_id) + + def start_iteration(self, version=1, data=None): + data = {} if not data else data + self.send_message( + messaging.RUNNER_METHOD_START_ITERATION, + payloads.RunnerPayload(version=version, data=data)) + + def stop_iteration(self, version=1, data=None): + data = {} if not data else data + self.send_message( + messaging.RUNNER_METHOD_STOP_ITERATION, + payloads.RunnerPayload(version=version, data=data)) diff --git a/yardstick/benchmark/runners/duration.py b/yardstick/benchmark/runners/duration.py index 60b0348c3..14fd8bb47 100644 --- a/yardstick/benchmark/runners/duration.py +++ b/yardstick/benchmark/runners/duration.py @@ -27,6 +27,7 @@ import traceback import time from yardstick.benchmark.runners import base +from yardstick.common import exceptions as y_exc LOG = logging.getLogger(__name__) @@ -70,13 +71,14 @@ def _worker_process(queue, cls, method_name, scenario_cfg, try: result = method(data) - except AssertionError as assertion: + except y_exc.SLAValidationError as error: # SLA validation failed in scenario, determine what to do now if sla_action == "assert": + benchmark.teardown() raise elif sla_action == "monitor": - LOG.warning("SLA validation failed: %s", assertion.args) - errors = assertion.args + LOG.warning("SLA validation failed: %s", error.args) + errors = error.args # catch all exceptions because with multiprocessing we can have un-picklable exception # problems https://bugs.python.org/issue9400 except Exception: # pylint: disable=broad-except diff --git a/yardstick/benchmark/runners/dynamictp.py b/yardstick/benchmark/runners/dynamictp.py index 63bfc823a..88d3c5704 100755 --- a/yardstick/benchmark/runners/dynamictp.py +++ b/yardstick/benchmark/runners/dynamictp.py @@ -27,6 +27,7 @@ import traceback import os from yardstick.benchmark.runners import base +from yardstick.common import exceptions as y_exc LOG = logging.getLogger(__name__) @@ -80,10 +81,10 @@ def _worker_process(queue, cls, method_name, scenario_cfg, try: method(data) - except AssertionError as assertion: - LOG.warning("SLA validation failed: %s" % assertion.args) + except y_exc.SLAValidationError as error: + LOG.warning("SLA validation failed: %s", error.args) too_high = True - except Exception as e: + except Exception as e: # pylint: disable=broad-except errors = traceback.format_exc() LOG.exception(e) diff --git a/yardstick/benchmark/runners/iteration.py b/yardstick/benchmark/runners/iteration.py index 20d6da054..4c88f3671 100644 --- a/yardstick/benchmark/runners/iteration.py +++ b/yardstick/benchmark/runners/iteration.py @@ -29,6 +29,7 @@ import traceback import os from yardstick.benchmark.runners import base +from yardstick.common import exceptions as y_exc LOG = logging.getLogger(__name__) @@ -75,13 +76,13 @@ def _worker_process(queue, cls, method_name, scenario_cfg, try: result = method(data) - except AssertionError as assertion: + except y_exc.SLAValidationError as error: # SLA validation failed in scenario, determine what to do now if sla_action == "assert": raise elif sla_action == "monitor": - LOG.warning("SLA validation failed: %s", assertion.args) - errors = assertion.args + LOG.warning("SLA validation failed: %s", error.args) + errors = error.args elif sla_action == "rate-control": try: scenario_cfg['options']['rate'] diff --git a/yardstick/benchmark/runners/iteration_ipc.py b/yardstick/benchmark/runners/iteration_ipc.py new file mode 100644 index 000000000..a0335fdc7 --- /dev/null +++ b/yardstick/benchmark/runners/iteration_ipc.py @@ -0,0 +1,205 @@ +# Copyright 2018: Intel Corporation +# All Rights Reserved. +# +# 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. + +"""A runner that runs a configurable number of times before it returns. Each + iteration has a configurable timeout. The loop control depends on the + feedback received from the running VNFs. The context PIDs from the VNFs + to listen the messages from are given in the scenario "setup" method. +""" + +import logging +import multiprocessing +import time +import traceback + +import os + +from yardstick.benchmark.runners import base as base_runner +from yardstick.common import exceptions +from yardstick.common import messaging +from yardstick.common import utils +from yardstick.common.messaging import consumer +from yardstick.common.messaging import payloads + + +LOG = logging.getLogger(__name__) + +QUEUE_PUT_TIMEOUT = 10 +ITERATION_TIMEOUT = 180 + + +class RunnerIterationIPCEndpoint(consumer.NotificationHandler): + """Endpoint class for ``RunnerIterationIPCConsumer``""" + + def tg_method_started(self, ctxt, **kwargs): + if ctxt['id'] in self._ctx_ids: + self._queue.put( + {'id': ctxt['id'], + 'action': messaging.TG_METHOD_STARTED, + 'payload': payloads.TrafficGeneratorPayload.dict_to_obj( + kwargs)}, + QUEUE_PUT_TIMEOUT) + + def tg_method_finished(self, ctxt, **kwargs): + if ctxt['id'] in self._ctx_ids: + self._queue.put( + {'id': ctxt['id'], + 'action': messaging.TG_METHOD_FINISHED, + 'payload': payloads.TrafficGeneratorPayload.dict_to_obj( + kwargs)}) + + def tg_method_iteration(self, ctxt, **kwargs): + if ctxt['id'] in self._ctx_ids: + self._queue.put( + {'id': ctxt['id'], + 'action': messaging.TG_METHOD_ITERATION, + 'payload': payloads.TrafficGeneratorPayload.dict_to_obj( + kwargs)}) + + +class RunnerIterationIPCConsumer(consumer.MessagingConsumer): + """MQ consumer for "IterationIPC" runner""" + + def __init__(self, _id, ctx_ids): + self._id = _id + self._queue = multiprocessing.Queue() + endpoints = [RunnerIterationIPCEndpoint(_id, ctx_ids, self._queue)] + super(RunnerIterationIPCConsumer, self).__init__( + messaging.TOPIC_TG, ctx_ids, endpoints) + self._kpi_per_id = {ctx: [] for ctx in ctx_ids} + self.iteration_index = None + + def is_all_kpis_received_in_iteration(self): + """Check if all producers registered have sent the ITERATION msg + + During the present iteration, all producers (traffic generators) must + start and finish the traffic injection, and at the end of the traffic + injection a TG_METHOD_ITERATION must be sent. This function will check + all KPIs in the present iteration are received. E.g.: + self.iteration_index = 2 + + self._kpi_per_id = { + 'ctx1': [kpi0, kpi1, kpi2], + 'ctx2': [kpi0, kpi1]} --> return False + + self._kpi_per_id = { + 'ctx1': [kpi0, kpi1, kpi2], + 'ctx2': [kpi0, kpi1, kpi2]} --> return True + """ + while not self._queue.empty(): + msg = self._queue.get(True, 1) + if msg['action'] == messaging.TG_METHOD_ITERATION: + id_iter_list = self._kpi_per_id[msg['id']] + id_iter_list.append(msg['payload'].kpi) + + return all(len(id_iter_list) == self.iteration_index + for id_iter_list in self._kpi_per_id.values()) + + +def _worker_process(queue, cls, method_name, scenario_cfg, + context_cfg, aborted, output_queue): # pragma: no cover + runner_cfg = scenario_cfg['runner'] + + timeout = runner_cfg.get('timeout', ITERATION_TIMEOUT) + iterations = runner_cfg.get('iterations', 1) + run_step = runner_cfg.get('run_step', 'setup,run,teardown') + LOG.info('Worker START. Iterations %d times, class %s', iterations, cls) + + runner_cfg['runner_id'] = os.getpid() + + benchmark = cls(scenario_cfg, context_cfg) + method = getattr(benchmark, method_name) + + if 'setup' not in run_step: + raise exceptions.RunnerIterationIPCSetupActionNeeded() + benchmark.setup() + producer_ctxs = benchmark.get_mq_ids() + if not producer_ctxs: + raise exceptions.RunnerIterationIPCNoCtxs() + + mq_consumer = RunnerIterationIPCConsumer(os.getpid(), producer_ctxs) + mq_consumer.start_rpc_server() + mq_producer = base_runner.RunnerProducer(scenario_cfg['task_id']) + + iteration_index = 1 + while 'run' in run_step: + LOG.debug('runner=%(runner)s seq=%(sequence)s START', + {'runner': runner_cfg['runner_id'], + 'sequence': iteration_index}) + data = {} + result = None + errors = '' + mq_consumer.iteration_index = iteration_index + mq_producer.start_iteration() + + try: + utils.wait_until_true( + mq_consumer.is_all_kpis_received_in_iteration, + timeout=timeout, sleep=2) + result = method(data) + except Exception: # pylint: disable=broad-except + errors = traceback.format_exc() + LOG.exception(errors) + + mq_producer.stop_iteration() + + if result: + output_queue.put(result, True, QUEUE_PUT_TIMEOUT) + benchmark_output = {'timestamp': time.time(), + 'sequence': iteration_index, + 'data': data, + 'errors': errors} + queue.put(benchmark_output, True, QUEUE_PUT_TIMEOUT) + + LOG.debug('runner=%(runner)s seq=%(sequence)s END', + {'runner': runner_cfg['runner_id'], + 'sequence': iteration_index}) + + iteration_index += 1 + if iteration_index > iterations or aborted.is_set(): + LOG.info('"IterationIPC" worker END') + break + + if 'teardown' in run_step: + try: + benchmark.teardown() + except Exception: + LOG.exception('Exception during teardown process') + mq_consumer.stop_rpc_server() + raise SystemExit(1) + + LOG.debug('Data queue size = %s', queue.qsize()) + LOG.debug('Output queue size = %s', output_queue.qsize()) + mq_consumer.stop_rpc_server() + + +class IterationIPCRunner(base_runner.Runner): + """Run a scenario for a configurable number of times. + + Each iteration has a configurable timeout. The loop control depends on the + feedback received from the running VNFs. The context PIDs from the VNFs to + listen the messages from are given in the scenario "setup" method. + """ + __execution_type__ = 'IterationIPC' + + def _run_benchmark(self, cls, method, scenario_cfg, context_cfg): + name = '{}-{}-{}'.format( + self.__execution_type__, scenario_cfg.get('type'), os.getpid()) + self.process = multiprocessing.Process( + name=name, + target=_worker_process, + args=(self.result_queue, cls, method, scenario_cfg, + context_cfg, self.aborted, self.output_queue)) + self.process.start() diff --git a/yardstick/benchmark/runners/proxduration.py b/yardstick/benchmark/runners/proxduration.py new file mode 100644 index 000000000..61a468fd3 --- /dev/null +++ b/yardstick/benchmark/runners/proxduration.py @@ -0,0 +1,165 @@ +# Copyright 2014: Mirantis Inc. +# All Rights Reserved. +# +# 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. + +# yardstick comment: this is a modified copy of +# rally/rally/benchmark/runners/constant.py + +"""A runner that runs a specific time before it returns +""" + +from __future__ import absolute_import + +import os +import multiprocessing +import logging +import traceback +import time + +from yardstick.benchmark.runners import base +from yardstick.common import exceptions as y_exc +from yardstick.common import constants + +LOG = logging.getLogger(__name__) + +def _worker_process(queue, cls, method_name, scenario_cfg, + context_cfg, aborted, output_queue): + + sequence = 1 + + runner_cfg = scenario_cfg['runner'] + + requested_interval = interval = runner_cfg.get("interval", 1) + duration = runner_cfg.get("duration", 60) + sampled = runner_cfg.get("sampled", False) + + LOG.info("Worker START, duration is %ds", duration) + LOG.debug("class is %s", cls) + + runner_cfg['runner_id'] = os.getpid() + + benchmark = cls(scenario_cfg, context_cfg) + benchmark.setup() + method = getattr(benchmark, method_name) + + sla_action = None + if "sla" in scenario_cfg: + sla_action = scenario_cfg["sla"].get("action", "assert") + + + start = time.time() + timeout = start + duration + while True: + + LOG.debug("runner=%(runner)s seq=%(sequence)s START", + {"runner": runner_cfg["runner_id"], "sequence": sequence}) + + data = {} + errors = "" + + benchmark.pre_run_wait_time(interval) + + if sampled: + try: + pre_adjustment = time.time() + result = method(data) + post_adjustment = time.time() + if requested_interval > post_adjustment - pre_adjustment: + interval = requested_interval - (post_adjustment - pre_adjustment) + else: + interval = 0 + + except y_exc.SLAValidationError as error: + # SLA validation failed in scenario, determine what to do now + if sla_action == "assert": + raise + elif sla_action == "monitor": + LOG.warning("SLA validation failed: %s", error.args) + errors = error.args + # catch all exceptions because with multiprocessing we can have un-picklable exception + # problems https://bugs.python.org/issue9400 + except Exception: # pylint: disable=broad-except + errors = traceback.format_exc() + LOG.exception("") + else: + if result: + # add timeout for put so we don't block test + # if we do timeout we don't care about dropping individual KPIs + output_queue.put(result, True, constants.QUEUE_PUT_TIMEOUT) + + benchmark_output = { + 'timestamp': time.time(), + 'sequence': sequence, + 'data': data, + 'errors': errors + } + + queue.put(benchmark_output, True, constants.QUEUE_PUT_TIMEOUT) + else: + LOG.debug("No sample collected ...Sequence %s", sequence) + + + sequence += 1 + + if (errors and sla_action is None) or time.time() > timeout or aborted.is_set(): + LOG.info("Worker END") + break + + try: + benchmark.teardown() + except Exception: + # catch any exception in teardown and convert to simple exception + # never pass exceptions back to multiprocessing, because some exceptions can + # be unpicklable + # https://bugs.python.org/issue9400 + LOG.exception("") + raise SystemExit(1) + + LOG.debug("queue.qsize() = %s", queue.qsize()) + LOG.debug("output_queue.qsize() = %s", output_queue.qsize()) + LOG.info("Exiting ProxDuration Runner...") + +class ProxDurationRunner(base.Runner): + """Run a scenario for a certain amount of time + +If the scenario ends before the time has elapsed, it will be started again. + + Parameters + duration - amount of time the scenario will be run for + type: int + unit: seconds + default: 60 sec + interval - time to wait between each scenario invocation + type: int + unit: seconds + default: 1 sec + sampled - Sample data is required yes/no + type: boolean + unit: True/False + default: False + confirmation - Number of confirmation retries + type: int + unit: retry attempts + default: 0 + """ + __execution_type__ = 'ProxDuration' + + def _run_benchmark(self, cls, method, scenario_cfg, context_cfg): + name = "{}-{}-{}".format(self.__execution_type__, scenario_cfg.get("type"), os.getpid()) + self.process = multiprocessing.Process( + name=name, + target=_worker_process, + args=(self.result_queue, cls, method, scenario_cfg, + context_cfg, self.aborted, self.output_queue)) + self.process.start() diff --git a/yardstick/benchmark/runners/search.py b/yardstick/benchmark/runners/search.py index 8037329b5..01a4292c7 100644 --- a/yardstick/benchmark/runners/search.py +++ b/yardstick/benchmark/runners/search.py @@ -33,6 +33,7 @@ from collections import Mapping from six.moves import zip from yardstick.benchmark.runners import base +from yardstick.common import exceptions as y_exc LOG = logging.getLogger(__name__) @@ -119,14 +120,14 @@ If the scenario ends before the time has elapsed, it will be started again. try: self.worker_helper(data) - except AssertionError as assertion: + except y_exc.SLAValidationError as error: # SLA validation failed in scenario, determine what to do now if self.sla_action == "assert": raise elif self.sla_action == "monitor": - LOG.warning("SLA validation failed: %s", assertion.args) - errors = assertion.args - except Exception as e: + LOG.warning("SLA validation failed: %s", error.args) + errors = error.args + except Exception as e: # pylint: disable=broad-except errors = traceback.format_exc() LOG.exception(e) diff --git a/yardstick/benchmark/runners/sequence.py b/yardstick/benchmark/runners/sequence.py index d6e3f7109..0148a45b2 100644 --- a/yardstick/benchmark/runners/sequence.py +++ b/yardstick/benchmark/runners/sequence.py @@ -30,6 +30,7 @@ import traceback import os from yardstick.benchmark.runners import base +from yardstick.common import exceptions as y_exc LOG = logging.getLogger(__name__) @@ -74,14 +75,14 @@ def _worker_process(queue, cls, method_name, scenario_cfg, try: result = method(data) - except AssertionError as assertion: + except y_exc.SLAValidationError as error: # SLA validation failed in scenario, determine what to do now if sla_action == "assert": raise elif sla_action == "monitor": - LOG.warning("SLA validation failed: %s", assertion.args) - errors = assertion.args - except Exception as e: + LOG.warning("SLA validation failed: %s", error.args) + errors = error.args + except Exception as e: # pylint: disable=broad-except errors = traceback.format_exc() LOG.exception(e) else: diff --git a/yardstick/benchmark/scenarios/availability/attacker/attacker_baremetal.py b/yardstick/benchmark/scenarios/availability/attacker/attacker_baremetal.py index 979e3ab14..53abd586b 100644 --- a/yardstick/benchmark/scenarios/availability/attacker/attacker_baremetal.py +++ b/yardstick/benchmark/scenarios/availability/attacker/attacker_baremetal.py @@ -23,7 +23,7 @@ def _execute_shell_command(command, stdin=None): output = [] try: output = subprocess.check_output(command, stdin=stdin, shell=True) - except Exception: + except Exception: # pylint: disable=broad-except exitcode = -1 LOG.error("exec command '%s' error:\n ", command, exc_info=True) @@ -49,8 +49,7 @@ class BaremetalAttacker(BaseAttacker): LOG.debug("jump_host ip:%s user:%s", jump_host['ip'], jump_host['user']) self.jump_connection = ssh.SSH.from_node( jump_host, - # why do we allow pwd for password? - defaults={"user": "root", "password": jump_host.get("pwd")} + defaults={"user": "root", "password": jump_host.get("password")} ) self.jump_connection.wait(timeout=600) LOG.debug("ssh jump host success!") @@ -59,7 +58,7 @@ class BaremetalAttacker(BaseAttacker): self.ipmi_ip = host.get("ipmi_ip", None) self.ipmi_user = host.get("ipmi_user", "root") - self.ipmi_pwd = host.get("ipmi_pwd", None) + self.ipmi_pwd = host.get("ipmi_password", None) self.fault_cfg = BaseAttacker.attacker_cfgs.get('bare-metal-down') self.check_script = self.get_script_fullpath( @@ -107,26 +106,3 @@ class BaremetalAttacker(BaseAttacker): else: _execute_shell_command(cmd, stdin=stdin_file) LOG.info("Recover fault END") - - -def _test(): # pragma: no cover - host = { - "ipmi_ip": "10.20.0.5", - "ipmi_user": "root", - "ipmi_pwd": "123456", - "ip": "10.20.0.5", - "user": "root", - "key_filename": "/root/.ssh/id_rsa" - } - context = {"node1": host} - attacker_cfg = { - 'fault_type': 'bear-metal-down', - 'host': 'node1', - } - ins = BaremetalAttacker(attacker_cfg, context) - ins.setup() - ins.inject_fault() - - -if __name__ == '__main__': # pragma: no cover - _test() diff --git a/yardstick/benchmark/scenarios/availability/scenario_general.py b/yardstick/benchmark/scenarios/availability/scenario_general.py index 1fadd2532..e2db03a70 100644 --- a/yardstick/benchmark/scenarios/availability/scenario_general.py +++ b/yardstick/benchmark/scenarios/availability/scenario_general.py @@ -58,16 +58,20 @@ class ScenarioGeneral(base.Scenario): self.director.stopMonitors() verify_result = self.director.verify() + service_not_found = False for k, v in self.director.data.items(): if v == 0: - result['sla_pass'] = 0 verify_result = False + service_not_found = True LOG.info("\033[92m The service process (%s) not found in the host environment", k) result['sla_pass'] = 1 if verify_result else 0 self.director.store_result(result) - assert verify_result is True, "The HA test case NOT passed" + self.verify_SLA( + verify_result, ("a service process was not found in the host " + "environment" if service_not_found + else "Director.verify() failed")) def teardown(self): self.director.knockoff() diff --git a/yardstick/benchmark/scenarios/availability/serviceha.py b/yardstick/benchmark/scenarios/availability/serviceha.py index 42941c6e7..7f976fdbc 100755 --- a/yardstick/benchmark/scenarios/availability/serviceha.py +++ b/yardstick/benchmark/scenarios/availability/serviceha.py @@ -29,6 +29,7 @@ class ServiceHA(base.Scenario): self.context_cfg = context_cfg self.setup_done = False self.data = {} + self.sla_pass = False def setup(self): """scenario setup""" @@ -69,23 +70,28 @@ class ServiceHA(base.Scenario): self.monitorMgr.wait_monitors() LOG.info("Monitor '%s' stop!", self.__scenario_type__) - sla_pass = self.monitorMgr.verify_SLA() + self.sla_pass = self.monitorMgr.verify_SLA() + service_not_found = False for k, v in self.data.items(): if v == 0: - sla_pass = False + self.sla_pass = False + service_not_found = True LOG.info("The service process (%s) not found in the host envrioment", k) - result['sla_pass'] = 1 if sla_pass else 0 + result['sla_pass'] = 1 if self.sla_pass else 0 self.monitorMgr.store_result(result) - assert sla_pass is True, "The HA test case NOT pass the SLA" - - return + self.verify_SLA( + self.sla_pass, ("a service process was not found in the host " + "environment" if service_not_found + else "MonitorMgr.verify_SLA() failed")) def teardown(self): """scenario teardown""" - for attacker in self.attackers: - attacker.recover() + # only recover when sla not pass + if not self.sla_pass: + for attacker in self.attackers: + attacker.recover() def _test(): # pragma: no cover diff --git a/yardstick/benchmark/scenarios/base.py b/yardstick/benchmark/scenarios/base.py index 58a02805c..90a87ac29 100644 --- a/yardstick/benchmark/scenarios/base.py +++ b/yardstick/benchmark/scenarios/base.py @@ -20,6 +20,7 @@ import six from stevedore import extension import yardstick.common.utils as utils +from yardstick.common import exceptions as y_exc def _iter_scenario_classes(scenario_type=None): @@ -61,6 +62,11 @@ class Scenario(object): """Time waited after executing the run method""" time.sleep(time_seconds) + def verify_SLA(self, condition, error_msg): + if not condition: + raise y_exc.SLAValidationError( + case_name=self.__scenario_type__, error_msg=error_msg) + @staticmethod def get_types(): """return a list of known runner type (class) names""" @@ -113,3 +119,7 @@ class Scenario(object): except TypeError: dic[k] = v return dic + + def get_mq_ids(self): # pragma: no cover + """Return stored MQ producer IDs, if defined""" + pass diff --git a/yardstick/benchmark/scenarios/compute/cyclictest.py b/yardstick/benchmark/scenarios/compute/cyclictest.py index 998463ef6..413709f3b 100644 --- a/yardstick/benchmark/scenarios/compute/cyclictest.py +++ b/yardstick/benchmark/scenarios/compute/cyclictest.py @@ -100,7 +100,7 @@ class Cyclictest(base.Scenario): def _run_setup_cmd(self, client, cmd): LOG.debug("Run cmd: %s", cmd) - status, stdout, stderr = client.execute(cmd) + status, _, stderr = client.execute(cmd) if status: if re.search(self.REBOOT_CMD_PATTERN, cmd): LOG.debug("Error on reboot") @@ -195,7 +195,7 @@ class Cyclictest(base.Scenario): if latency > sla_latency: sla_error += "%s latency %d > sla:max_%s_latency(%d); " % \ (t, latency, t, sla_latency) - assert sla_error == "", sla_error + self.verify_SLA(sla_error == "", sla_error) def _test(): # pragma: no cover diff --git a/yardstick/benchmark/scenarios/compute/lmbench.py b/yardstick/benchmark/scenarios/compute/lmbench.py index 801f7fa80..2237e49e0 100644 --- a/yardstick/benchmark/scenarios/compute/lmbench.py +++ b/yardstick/benchmark/scenarios/compute/lmbench.py @@ -119,8 +119,8 @@ class Lmbench(base.Scenario): cmd = "sudo bash lmbench_latency_for_cache.sh %d %d" % \ (repetition, warmup) else: - raise RuntimeError("No such test_type: %s for Lmbench scenario", - test_type) + raise RuntimeError("No such test_type: %s for Lmbench scenario" + % test_type) LOG.debug("Executing command: %s", cmd) status, stdout, stderr = self.client.execute(cmd) @@ -157,7 +157,7 @@ class Lmbench(base.Scenario): if sla_latency < cache_latency: sla_error += "latency %f > sla:max_latency(%f); " \ % (cache_latency, sla_latency) - assert sla_error == "", sla_error + self.verify_SLA(sla_error == "", sla_error) def _test(): diff --git a/yardstick/benchmark/scenarios/compute/perf.py b/yardstick/benchmark/scenarios/compute/perf.py index 0b8ed9b28..b973211f1 100644 --- a/yardstick/benchmark/scenarios/compute/perf.py +++ b/yardstick/benchmark/scenarios/compute/perf.py @@ -93,7 +93,7 @@ class Perf(base.Scenario): % (load, duration, events_string) LOG.debug("Executing command: %s", cmd) - status, stdout, stderr = self.client.execute(cmd) + status, stdout, _ = self.client.execute(cmd) if status: raise RuntimeError(stdout) @@ -105,16 +105,14 @@ class Perf(base.Scenario): exp_val = self.scenario_cfg['sla']['expected_value'] smaller_than_exp = 'smaller_than_expected' \ in self.scenario_cfg['sla'] - - if metric not in result: - assert False, "Metric (%s) not found." % metric - else: - if smaller_than_exp: - assert result[metric] < exp_val, "%s %d >= %d (sla); " \ - % (metric, result[metric], exp_val) - else: - assert result[metric] >= exp_val, "%s %d < %d (sla); " \ - % (metric, result[metric], exp_val) + self.verify_SLA(metric in result, + "Metric (%s) not found." % metric) + self.verify_SLA( + not smaller_than_exp, + "%s %d >= %d (sla); " % (metric, result[metric], exp_val)) + self.verify_SLA( + result[metric] >= exp_val, + "%s %d < %d (sla); " % (metric, result[metric], exp_val)) def _test(): diff --git a/yardstick/benchmark/scenarios/compute/qemu_migrate.py b/yardstick/benchmark/scenarios/compute/qemu_migrate.py index 2de1270ef..975c90b22 100644 --- a/yardstick/benchmark/scenarios/compute/qemu_migrate.py +++ b/yardstick/benchmark/scenarios/compute/qemu_migrate.py @@ -56,7 +56,7 @@ class QemuMigrate(base.Scenario): def _run_setup_cmd(self, client, cmd): LOG.debug("Run cmd: %s", cmd) - status, stdout, stderr = client.execute(cmd) + status, _, stderr = client.execute(cmd) if status: if re.search(self.REBOOT_CMD_PATTERN, cmd): LOG.debug("Error on reboot") @@ -127,7 +127,7 @@ class QemuMigrate(base.Scenario): if timevalue > sla_time: sla_error += "%s timevalue %d > sla:max_%s(%d); " % \ (t, timevalue, t, sla_time) - assert sla_error == "", sla_error + self.verify_SLA(sla_error == "", sla_error) def _test(): # pragma: no cover diff --git a/yardstick/benchmark/scenarios/compute/ramspeed.py b/yardstick/benchmark/scenarios/compute/ramspeed.py index ca64935dd..4daf776ff 100644 --- a/yardstick/benchmark/scenarios/compute/ramspeed.py +++ b/yardstick/benchmark/scenarios/compute/ramspeed.py @@ -121,8 +121,8 @@ class Ramspeed(base.Scenario): (test_id, load, block_size) # only the test_id 1-6 will be used in this scenario else: - raise RuntimeError("No such type_id: %s for Ramspeed scenario", - test_id) + raise RuntimeError("No such type_id: %s for Ramspeed scenario" + % test_id) LOG.debug("Executing command: %s", cmd) status, stdout, stderr = self.client.execute(cmd) @@ -140,4 +140,4 @@ class Ramspeed(base.Scenario): if bw < sla_min_bw: sla_error += "Bandwidth %f < " \ "sla:min_bandwidth(%f)" % (bw, sla_min_bw) - assert sla_error == "", sla_error + self.verify_SLA(sla_error == "", sla_error) diff --git a/yardstick/benchmark/scenarios/compute/unixbench.py b/yardstick/benchmark/scenarios/compute/unixbench.py index cdb345717..3cea31694 100644 --- a/yardstick/benchmark/scenarios/compute/unixbench.py +++ b/yardstick/benchmark/scenarios/compute/unixbench.py @@ -125,7 +125,7 @@ class Unixbench(base.Scenario): if score < sla_score: sla_error += "%s score %f < sla:%s_score(%f); " % \ (t, score, t, sla_score) - assert sla_error == "", sla_error + self.verify_SLA(sla_error == "", sla_error) def _test(): # pragma: no cover diff --git a/yardstick/benchmark/scenarios/lib/create_image.py b/yardstick/benchmark/scenarios/lib/create_image.py index bcffc7452..d057894a9 100644 --- a/yardstick/benchmark/scenarios/lib/create_image.py +++ b/yardstick/benchmark/scenarios/lib/create_image.py @@ -6,14 +6,11 @@ # which accompanies this distribution, and is available at # 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__) @@ -26,20 +23,23 @@ class CreateImage(base.Scenario): def __init__(self, scenario_cfg, context_cfg): self.scenario_cfg = scenario_cfg self.context_cfg = context_cfg - self.options = self.scenario_cfg['options'] - - self.image_name = self.options.get("image_name", "TestImage") - self.file_path = self.options.get("file_path", None) - self.disk_format = self.options.get("disk_format", "qcow2") - self.container_format = self.options.get("container_format", "bare") - self.min_disk = self.options.get("min_disk", 0) - self.min_ram = self.options.get("min_ram", 0) - self.protected = self.options.get("protected", False) - self.public = self.options.get("public", "public") - self.tags = self.options.get("tags", []) - self.custom_property = self.options.get("property", {}) - - self.glance_client = op_utils.get_glance_client() + self.options = self.scenario_cfg["options"] + + self.name = self.options["image_name"] + self.file_name = self.options.get("file_name") + self.container = self.options.get("container", 'images') + self.md5 = self.options.get("md5") + self.sha256 = self.options.get("sha256") + self.disk_format = self.options.get("disk_format") + self.container_format = self.options.get("container_format",) + self.disable_vendor_agent = self.options.get("disable_vendor_agent", True) + self.wait = self.options.get("wait", True) + self.timeout = self.options.get("timeout", 3600) + self.allow_duplicates = self.options.get("allow_duplicates", False) + self.meta = self.options.get("meta") + self.volume = self.options.get("volume") + + self.shade_client = openstack_utils.get_shade_client() self.setup_done = False @@ -54,19 +54,22 @@ class CreateImage(base.Scenario): if not self.setup_done: self.setup() - image_id = op_utils.create_image(self.glance_client, self.image_name, - self.file_path, self.disk_format, - self.container_format, self.min_disk, - self.min_ram, self.protected, self.tags, - self.public, **self.custom_property) - - if image_id: - LOG.info("Create image successful!") - values = [image_id] - - else: - LOG.info("Create image failed!") - values = [] - - keys = self.scenario_cfg.get('output', '').split() + image_id = openstack_utils.create_image( + self.shade_client, self.name, filename=self.file_name, + container=self.container, md5=self.md5, sha256=self.sha256, + disk_format=self.disk_format, + container_format=self.container_format, + disable_vendor_agent=self.disable_vendor_agent, wait=self.wait, + timeout=self.timeout, allow_duplicates=self.allow_duplicates, + meta=self.meta, volume=self.volume) + + if not image_id: + result.update({"image_create": 0}) + LOG.error("Create image failed!") + raise exceptions.ScenarioCreateImageError + + result.update({"image_create": 1}) + LOG.info("Create image successful!") + keys = self.scenario_cfg.get("output", '').split() + values = [image_id] return self._push_to_outputs(keys, values) diff --git a/yardstick/benchmark/scenarios/lib/delete_image.py b/yardstick/benchmark/scenarios/lib/delete_image.py index 0e3a853e5..008f104b2 100644 --- a/yardstick/benchmark/scenarios/lib/delete_image.py +++ b/yardstick/benchmark/scenarios/lib/delete_image.py @@ -7,13 +7,11 @@ # 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__) @@ -26,12 +24,14 @@ class DeleteImage(base.Scenario): def __init__(self, scenario_cfg, context_cfg): self.scenario_cfg = scenario_cfg self.context_cfg = context_cfg - self.options = self.scenario_cfg['options'] + self.options = self.scenario_cfg["options"] - self.image_name = self.options.get("image_name", "TestImage") - self.image_id = None + self.image_name_or_id = self.options["name_or_id"] + self.wait = self.options.get("wait", False) + self.timeout = self.options.get("timeout", 3600) + self.delete_objects = self.options.get("delete_objects", True) - self.glance_client = op_utils.get_glance_client() + self.shade_client = openstack_utils.get_shade_client() self.setup_done = False @@ -46,16 +46,14 @@ class DeleteImage(base.Scenario): if not self.setup_done: self.setup() - self.image_id = op_utils.get_image_id(self.glance_client, self.image_name) - LOG.info("Deleting image: %s", self.image_name) - status = op_utils.delete_image(self.glance_client, self.image_id) + status = openstack_utils.delete_image( + self.shade_client, self.image_name_or_id, wait=self.wait, + timeout=self.timeout, delete_objects=self.delete_objects) - if status: - LOG.info("Delete image successful!") - values = [status] - else: - LOG.info("Delete image failed!") - values = [] + if not status: + result.update({"delete_image": 0}) + LOG.error("Delete image failed!") + raise exceptions.ScenarioDeleteImageError - keys = self.scenario_cfg.get('output', '').split() - return self._push_to_outputs(keys, values) + result.update({"delete_image": 1}) + LOG.info("Delete image successful!") diff --git a/yardstick/benchmark/scenarios/networking/iperf3.py b/yardstick/benchmark/scenarios/networking/iperf3.py index 98c45990e..51e044e7b 100644 --- a/yardstick/benchmark/scenarios/networking/iperf3.py +++ b/yardstick/benchmark/scenarios/networking/iperf3.py @@ -92,7 +92,7 @@ For more info see http://software.es.net/iperf def teardown(self): LOG.debug("teardown") self.host.close() - status, stdout, stderr = self.target.execute("pkill iperf3") + status, _, stderr = self.target.execute("pkill iperf3") if status: LOG.warning(stderr) self.target.close() @@ -145,7 +145,7 @@ For more info see http://software.es.net/iperf LOG.debug("Executing command: %s", cmd) - status, stdout, stderr = self.host.execute(cmd) + status, stdout, _ = self.host.execute(cmd) if status: # error cause in json dict on stdout raise RuntimeError(stdout) @@ -165,16 +165,17 @@ For more info see http://software.es.net/iperf bit_per_second = \ int(iperf_result["end"]["sum_received"]["bits_per_second"]) bytes_per_second = bit_per_second / 8 - assert bytes_per_second >= sla_bytes_per_second, \ - "bytes_per_second %d < sla:bytes_per_second (%d); " % \ - (bytes_per_second, sla_bytes_per_second) + self.verify_SLA( + bytes_per_second >= sla_bytes_per_second, + "bytes_per_second %d < sla:bytes_per_second (%d); " + % (bytes_per_second, sla_bytes_per_second)) else: sla_jitter = float(sla_iperf["jitter"]) jitter_ms = float(iperf_result["end"]["sum"]["jitter_ms"]) - assert jitter_ms <= sla_jitter, \ - "jitter_ms %f > sla:jitter %f; " % \ - (jitter_ms, sla_jitter) + self.verify_SLA(jitter_ms <= sla_jitter, + "jitter_ms %f > sla:jitter %f; " + % (jitter_ms, sla_jitter)) def _test(): diff --git a/yardstick/benchmark/scenarios/networking/moongen_testpmd.py b/yardstick/benchmark/scenarios/networking/moongen_testpmd.py index 86173c9da..e3bd7af46 100644 --- a/yardstick/benchmark/scenarios/networking/moongen_testpmd.py +++ b/yardstick/benchmark/scenarios/networking/moongen_testpmd.py @@ -367,9 +367,10 @@ ports = {0,1}, 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"]) + self.verify_SLA( + 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""" diff --git a/yardstick/benchmark/scenarios/networking/netperf.py b/yardstick/benchmark/scenarios/networking/netperf.py index 33c02d409..9f1a81413 100755 --- a/yardstick/benchmark/scenarios/networking/netperf.py +++ b/yardstick/benchmark/scenarios/networking/netperf.py @@ -138,9 +138,9 @@ class Netperf(base.Scenario): sla_max_mean_latency = int( self.scenario_cfg["sla"]["mean_latency"]) - assert mean_latency <= sla_max_mean_latency, \ - "mean_latency %f > sla_max_mean_latency(%f); " % \ - (mean_latency, sla_max_mean_latency) + self.verify_SLA(mean_latency <= sla_max_mean_latency, + "mean_latency %f > sla_max_mean_latency(%f); " + % (mean_latency, sla_max_mean_latency)) def _test(): diff --git a/yardstick/benchmark/scenarios/networking/netperf_node.py b/yardstick/benchmark/scenarios/networking/netperf_node.py index d52e6b9e1..0ad2ecff5 100755 --- a/yardstick/benchmark/scenarios/networking/netperf_node.py +++ b/yardstick/benchmark/scenarios/networking/netperf_node.py @@ -156,9 +156,10 @@ class NetperfNode(base.Scenario): sla_max_mean_latency = int( self.scenario_cfg["sla"]["mean_latency"]) - assert mean_latency <= sla_max_mean_latency, \ - "mean_latency %f > sla_max_mean_latency(%f); " % \ - (mean_latency, sla_max_mean_latency) + self.verify_SLA( + mean_latency <= sla_max_mean_latency, + "mean_latency %f > sla_max_mean_latency(%f); " + % (mean_latency, sla_max_mean_latency)) def teardown(self): """remove netperf from nodes after test""" diff --git a/yardstick/benchmark/scenarios/networking/nstat.py b/yardstick/benchmark/scenarios/networking/nstat.py index 10c560769..ea067f8ab 100644 --- a/yardstick/benchmark/scenarios/networking/nstat.py +++ b/yardstick/benchmark/scenarios/networking/nstat.py @@ -121,4 +121,4 @@ class Nstat(base.Scenario): if rate > sla_rate: sla_error += "%s rate %f > sla:%s_rate(%f); " % \ (i, rate, i, sla_rate) - assert sla_error == "", sla_error + self.verify_SLA(sla_error == "", sla_error) diff --git a/yardstick/benchmark/scenarios/networking/ping.py b/yardstick/benchmark/scenarios/networking/ping.py index e7d9beea8..6caeab5ef 100644 --- a/yardstick/benchmark/scenarios/networking/ping.py +++ b/yardstick/benchmark/scenarios/networking/ping.py @@ -91,9 +91,10 @@ class Ping(base.Scenario): result.update(utils.flatten_dict_key(ping_result)) if sla_max_rtt is not None: sla_max_rtt = float(sla_max_rtt) - assert rtt_result[target_vm_name] <= sla_max_rtt,\ - "rtt %f > sla: max_rtt(%f); " % \ - (rtt_result[target_vm_name], sla_max_rtt) + self.verify_SLA( + rtt_result[target_vm_name] <= sla_max_rtt, + "rtt %f > sla: max_rtt(%f); " + % (rtt_result[target_vm_name], sla_max_rtt)) else: LOG.error("ping '%s' '%s' timeout", options, target_vm) # we need to specify a result to satisfy influxdb schema @@ -102,13 +103,12 @@ class Ping(base.Scenario): rtt_result[target_vm_name] = float(self.PING_ERROR_RTT) # store result before potential AssertionError result.update(utils.flatten_dict_key(ping_result)) - if sla_max_rtt is not None: - raise AssertionError("packet dropped rtt {:f} > sla: max_rtt({:f})".format( - rtt_result[target_vm_name], sla_max_rtt)) - - else: - raise AssertionError( - "packet dropped rtt {:f}".format(rtt_result[target_vm_name])) + self.verify_SLA(sla_max_rtt is None, + "packet dropped rtt %f > sla: max_rtt(%f)" + % (rtt_result[target_vm_name], sla_max_rtt)) + self.verify_SLA(False, + "packet dropped rtt %f" + % (rtt_result[target_vm_name])) def _test(): # pragma: no cover diff --git a/yardstick/benchmark/scenarios/networking/ping6.py b/yardstick/benchmark/scenarios/networking/ping6.py index 74855a10f..377278004 100644 --- a/yardstick/benchmark/scenarios/networking/ping6.py +++ b/yardstick/benchmark/scenarios/networking/ping6.py @@ -59,8 +59,7 @@ class Ping6(base.Scenario): # pragma: no cover self._ssh_host(node_name) self.client._put_file_shell( self.pre_setup_script, '~/pre_setup.sh') - status, stdout, stderr = self.client.execute( - "sudo bash pre_setup.sh") + self.client.execute("sudo bash pre_setup.sh") def _get_controller_node(self, host_list): for host_name in host_list: @@ -122,7 +121,7 @@ class Ping6(base.Scenario): # pragma: no cover cmd = "sudo bash %s %s %s" % \ (setup_bash_file, self.openrc, self.external_network) LOG.debug("Executing setup command: %s", cmd) - status, stdout, stderr = self.client.execute(cmd) + self.client.execute(cmd) self.setup_done = True @@ -171,8 +170,9 @@ class Ping6(base.Scenario): # pragma: no cover result["rtt"] = float(stdout) if "sla" in self.scenario_cfg: sla_max_rtt = int(self.scenario_cfg["sla"]["max_rtt"]) - assert result["rtt"] <= sla_max_rtt, \ - "rtt %f > sla:max_rtt(%f); " % (result["rtt"], sla_max_rtt) + self.verify_SLA(result["rtt"] <= sla_max_rtt, + "rtt %f > sla:max_rtt(%f); " + % (result["rtt"], sla_max_rtt)) else: LOG.error("ping6 timeout!!!") self.run_done = True @@ -216,5 +216,4 @@ class Ping6(base.Scenario): # pragma: no cover self._ssh_host(node_name) self.client._put_file_shell( self.post_teardown_script, '~/post_teardown.sh') - status, stdout, stderr = self.client.execute( - "sudo bash post_teardown.sh") + self.client.execute("sudo bash post_teardown.sh") diff --git a/yardstick/benchmark/scenarios/networking/pktgen.py b/yardstick/benchmark/scenarios/networking/pktgen.py index b79b91539..c78108adb 100644 --- a/yardstick/benchmark/scenarios/networking/pktgen.py +++ b/yardstick/benchmark/scenarios/networking/pktgen.py @@ -87,7 +87,7 @@ class Pktgen(base.Scenario): self.server.send_command(cmd) self.client.send_command(cmd) - """multiqueue setup""" + # multiqueue setup if not self._is_irqbalance_disabled(): self._disable_irqbalance() @@ -112,18 +112,14 @@ class Pktgen(base.Scenario): def _get_vnic_driver_name(self): cmd = "readlink /sys/class/net/%s/device/driver" % self.vnic_name LOG.debug("Executing command: %s", cmd) - status, stdout, stderr = self.server.execute(cmd) - if status: - raise RuntimeError(stderr) + _, stdout, _ = self.server.execute(cmd, raise_on_error=True) return os.path.basename(stdout.strip()) def _is_irqbalance_disabled(self): """Did we disable irqbalance already in the guest?""" is_disabled = False cmd = "grep ENABLED /etc/default/irqbalance" - status, stdout, stderr = self.server.execute(cmd) - if status: - raise RuntimeError(stderr) + _, stdout, _ = self.server.execute(cmd, raise_on_error=True) if "0" in stdout: is_disabled = True @@ -132,49 +128,35 @@ class Pktgen(base.Scenario): def _disable_irqbalance(self): cmd = "sudo sed -i -e 's/ENABLED=\"1\"/ENABLED=\"0\"/g' " \ "/etc/default/irqbalance" - status, stdout, stderr = self.server.execute(cmd) - status, stdout, stderr = self.client.execute(cmd) - if status: - raise RuntimeError(stderr) + self.server.run(cmd) + self.client.run(cmd) cmd = "sudo service irqbalance stop" - status, stdout, stderr = self.server.execute(cmd) - status, stdout, stderr = self.client.execute(cmd) - if status: - raise RuntimeError(stderr) + self.server.run(cmd) + self.client.run(cmd) cmd = "sudo service irqbalance disable" - status, stdout, stderr = self.server.execute(cmd) - status, stdout, stderr = self.client.execute(cmd) - if status: - raise RuntimeError(stderr) + self.server.run(cmd) + self.client.run(cmd) def _setup_irqmapping_ovs(self, queue_number): cmd = "grep 'virtio0-input.0' /proc/interrupts |" \ "awk '{match($0,/ +[0-9]+/)} " \ "{print substr($1,RSTART,RLENGTH-1)}'" - status, stdout, stderr = self.server.execute(cmd) - if status: - raise RuntimeError(stderr) + _, stdout, _ = self.server.execute(cmd, raise_on_error=True) cmd = "echo 1 | sudo tee /proc/irq/%s/smp_affinity" % (int(stdout)) - status, stdout, stderr = self.server.execute(cmd) - status, stdout, stderr = self.client.execute(cmd) - if status: - raise RuntimeError(stderr) + self.server.run(cmd) + self.client.run(cmd) cmd = "grep 'virtio0-output.0' /proc/interrupts |" \ "awk '{match($0,/ +[0-9]+/)} " \ "{print substr($1,RSTART,RLENGTH-1)}'" - status, stdout, stderr = self.server.execute(cmd) - if status: - raise RuntimeError(stderr) + _, stdout, _ = self.server.execute(cmd, raise_on_error=True) cmd = "echo 1 | sudo tee /proc/irq/%s/smp_affinity" % (int(stdout)) - status, stdout, stderr = self.server.execute(cmd) - status, stdout, stderr = self.client.execute(cmd) - if status: - raise RuntimeError(stderr) + self.server.run(cmd) + self.client.run(cmd) if queue_number == 1: return @@ -186,44 +168,32 @@ class Pktgen(base.Scenario): cmd = "grep 'virtio0-input.%s' /proc/interrupts |" \ "awk '{match($0,/ +[0-9]+/)} " \ "{print substr($1,RSTART,RLENGTH-1)}'" % (i) - status, stdout, stderr = self.server.execute(cmd) - if status: - raise RuntimeError(stderr) + _, stdout, _ = self.server.execute(cmd, raise_on_error=True) cmd = "echo %s | sudo tee /proc/irq/%s/smp_affinity" \ % (smp_affinity_mask, int(stdout)) - status, stdout, stderr = self.server.execute(cmd) - status, stdout, stderr = self.client.execute(cmd) - if status: - raise RuntimeError(stderr) + self.server.run(cmd) + self.client.run(cmd) cmd = "grep 'virtio0-output.%s' /proc/interrupts |" \ "awk '{match($0,/ +[0-9]+/)} " \ "{print substr($1,RSTART,RLENGTH-1)}'" % (i) - status, stdout, stderr = self.server.execute(cmd) - if status: - raise RuntimeError(stderr) + _, stdout, _ = self.server.execute(cmd, raise_on_error=True) cmd = "echo %s | sudo tee /proc/irq/%s/smp_affinity" \ % (smp_affinity_mask, int(stdout)) - status, stdout, stderr = self.server.execute(cmd) - status, stdout, stderr = self.client.execute(cmd) - if status: - raise RuntimeError(stderr) + self.server.run(cmd) + self.client.run(cmd) def _setup_irqmapping_sriov(self, queue_number): cmd = "grep '%s-TxRx-0' /proc/interrupts |" \ "awk '{match($0,/ +[0-9]+/)} " \ "{print substr($1,RSTART,RLENGTH-1)}'" % self.vnic_name - status, stdout, stderr = self.server.execute(cmd) - if status: - raise RuntimeError(stderr) + _, stdout, _ = self.server.execute(cmd, raise_on_error=True) cmd = "echo 1 | sudo tee /proc/irq/%s/smp_affinity" % (int(stdout)) - status, stdout, stderr = self.server.execute(cmd) - status, stdout, stderr = self.client.execute(cmd) - if status: - raise RuntimeError(stderr) + self.server.run(cmd) + self.client.run(cmd) if queue_number == 1: return @@ -234,24 +204,18 @@ class Pktgen(base.Scenario): cmd = "grep '%s-TxRx-%s' /proc/interrupts |" \ "awk '{match($0,/ +[0-9]+/)} " \ "{print substr($1,RSTART,RLENGTH-1)}'" % (self.vnic_name, i) - status, stdout, stderr = self.server.execute(cmd) - if status: - raise RuntimeError(stderr) + _, stdout, _ = self.server.execute(cmd, raise_on_error=True) cmd = "echo %s | sudo tee /proc/irq/%s/smp_affinity" \ % (smp_affinity_mask, int(stdout)) - status, stdout, stderr = self.server.execute(cmd) - status, stdout, stderr = self.client.execute(cmd) - if status: - raise RuntimeError(stderr) + self.server.run(cmd) + self.client.run(cmd) def _get_sriov_queue_number(self): """Get queue number from server as both VMs are the same""" cmd = "grep %s-TxRx- /proc/interrupts | wc -l" % self.vnic_name LOG.debug("Executing command: %s", cmd) - status, stdout, stderr = self.server.execute(cmd) - if status: - raise RuntimeError(stderr) + _, stdout, _ = self.server.execute(cmd, raise_on_error=True) return int(stdout) def _get_available_queue_number(self): @@ -259,9 +223,7 @@ class Pktgen(base.Scenario): cmd = "sudo ethtool -l %s | grep Combined | head -1 |" \ "awk '{printf $2}'" % self.vnic_name LOG.debug("Executing command: %s", cmd) - status, stdout, stderr = self.server.execute(cmd) - if status: - raise RuntimeError(stderr) + _, stdout, _ = self.server.execute(cmd, raise_on_error=True) return int(stdout) def _get_usable_queue_number(self): @@ -269,9 +231,7 @@ class Pktgen(base.Scenario): cmd = "sudo ethtool -l %s | grep Combined | tail -1 |" \ "awk '{printf $2}'" % self.vnic_name LOG.debug("Executing command: %s", cmd) - status, stdout, stderr = self.server.execute(cmd) - if status: - raise RuntimeError(stderr) + _, stdout, _ = self.server.execute(cmd, raise_on_error=True) return int(stdout) def _enable_ovs_multiqueue(self): @@ -282,10 +242,8 @@ class Pktgen(base.Scenario): cmd = "sudo ethtool -L %s combined %s" % \ (self.vnic_name, available_queue_number) LOG.debug("Executing command: %s", cmd) - status, stdout, stderr = self.server.execute(cmd) - status, stdout, stderr = self.client.execute(cmd) - if status: - raise RuntimeError(stderr) + self.server.run(cmd) + self.client.run(cmd) return available_queue_number def _iptables_setup(self): @@ -294,9 +252,7 @@ class Pktgen(base.Scenario): "sudo iptables -A INPUT -p udp --dport 1000:%s -j DROP" \ % (1000 + self.number_of_ports) LOG.debug("Executing command: %s", cmd) - status, _, stderr = self.server.execute(cmd, timeout=SSH_TIMEOUT) - if status: - raise RuntimeError(stderr) + self.server.run(cmd, timeout=SSH_TIMEOUT) def _iptables_get_result(self): """Get packet statistics from server""" @@ -304,9 +260,7 @@ class Pktgen(base.Scenario): "awk '/dpts:1000:%s/ {{printf \"%%s\", $1}}'" \ % (1000 + self.number_of_ports) LOG.debug("Executing command: %s", cmd) - status, stdout, stderr = self.server.execute(cmd) - if status: - raise RuntimeError(stderr) + _, stdout, _ = self.server.execute(cmd, raise_on_error=True) return int(stdout) def run(self, result): @@ -356,10 +310,8 @@ class Pktgen(base.Scenario): duration, queue_number, pps) LOG.debug("Executing command: %s", cmd) - status, stdout, stderr = self.client.execute(cmd, timeout=SSH_TIMEOUT) - - if status: - raise RuntimeError(stderr) + _, stdout, _ = self.client.execute(cmd, raise_on_error=True, + timeout=SSH_TIMEOUT) result.update(jsonutils.loads(stdout)) @@ -374,8 +326,8 @@ class Pktgen(base.Scenario): if "sla" in self.scenario_cfg: LOG.debug("Lost packets %d - Lost ppm %d", (sent - received), ppm) sla_max_ppm = int(self.scenario_cfg["sla"]["max_ppm"]) - assert ppm <= sla_max_ppm, "ppm %d > sla_max_ppm %d; " \ - % (ppm, sla_max_ppm) + self.verify_SLA(ppm <= sla_max_ppm, + "ppm %d > sla_max_ppm %d; " % (ppm, sla_max_ppm)) def _test(): # pragma: no cover diff --git a/yardstick/benchmark/scenarios/networking/pktgen_dpdk.py b/yardstick/benchmark/scenarios/networking/pktgen_dpdk.py index 9a7b975a2..efb7d8b5d 100644 --- a/yardstick/benchmark/scenarios/networking/pktgen_dpdk.py +++ b/yardstick/benchmark/scenarios/networking/pktgen_dpdk.py @@ -113,10 +113,7 @@ cat ~/result.log -vT \ {print substr($0,RSTART,RLENGTH)}' \ |grep -v ^$ |awk '{if ($2 != 0) print $2}'\ """ - client_status, client_stdout, client_stderr = self.client.execute(cmd) - - if client_status: - raise RuntimeError(client_stderr) + _, client_stdout, _ = self.client.execute(cmd, raise_on_error=True) avg_latency = 0 if client_stdout: @@ -135,4 +132,4 @@ cat ~/result.log -vT \ LOG.info("sla_max_latency: %d", sla_max_latency) debug_info = "avg_latency %d > sla_max_latency %d" \ % (avg_latency, sla_max_latency) - assert avg_latency <= sla_max_latency, debug_info + self.verify_SLA(avg_latency <= sla_max_latency, debug_info) diff --git a/yardstick/benchmark/scenarios/networking/pktgen_dpdk_throughput.py b/yardstick/benchmark/scenarios/networking/pktgen_dpdk_throughput.py index 497e59ee8..97b9cf73f 100644 --- a/yardstick/benchmark/scenarios/networking/pktgen_dpdk_throughput.py +++ b/yardstick/benchmark/scenarios/networking/pktgen_dpdk_throughput.py @@ -143,11 +143,11 @@ class PktgenDPDK(base.Scenario): cmd = "ip a | grep eth1 2>/dev/null" LOG.debug("Executing command: %s in %s", cmd, host) if "server" in host: - status, stdout, stderr = self.server.execute(cmd) + _, stdout, _ = self.server.execute(cmd) if stdout: is_run = False else: - status, stdout, stderr = self.client.execute(cmd) + _, stdout, _ = self.client.execute(cmd) if stdout: is_run = False @@ -222,5 +222,5 @@ class PktgenDPDK(base.Scenario): ppm += (sent - received) % sent > 0 LOG.debug("Lost packets %d - Lost ppm %d", (sent - received), ppm) sla_max_ppm = int(self.scenario_cfg["sla"]["max_ppm"]) - assert ppm <= sla_max_ppm, "ppm %d > sla_max_ppm %d; " \ - % (ppm, sla_max_ppm) + self.verify_SLA(ppm <= sla_max_ppm, "ppm %d > sla_max_ppm %d; " + % (ppm, sla_max_ppm)) diff --git a/yardstick/benchmark/scenarios/networking/vnf_generic.py b/yardstick/benchmark/scenarios/networking/vnf_generic.py index 78f866e25..10f10d4e6 100644 --- a/yardstick/benchmark/scenarios/networking/vnf_generic.py +++ b/yardstick/benchmark/scenarios/networking/vnf_generic.py @@ -13,20 +13,20 @@ # limitations under the License. import copy -import logging -import time - import ipaddress from itertools import chain +import logging import os import sys +import time import six import yaml +from yardstick.benchmark.contexts import base as context_base from yardstick.benchmark.scenarios import base as scenario_base -from yardstick.error import IncorrectConfig from yardstick.common.constants import LOG_DIR +from yardstick.common import exceptions from yardstick.common.process import terminate_children from yardstick.common import utils from yardstick.network_services.collector.subscriber import Collector @@ -37,6 +37,7 @@ from yardstick.network_services.traffic_profile import base as tprofile_base from yardstick.network_services.utils import get_nsb_option from yardstick import ssh + traffic_profile.register_modules() @@ -49,7 +50,7 @@ class NetworkServiceTestCase(scenario_base.Scenario): __scenario_type__ = "NSPerf" - def __init__(self, scenario_cfg, context_cfg): # Yardstick API + def __init__(self, scenario_cfg, context_cfg): # pragma: no cover super(NetworkServiceTestCase, self).__init__() self.scenario_cfg = scenario_cfg self.context_cfg = context_cfg @@ -60,39 +61,39 @@ class NetworkServiceTestCase(scenario_base.Scenario): self.traffic_profile = None self.node_netdevs = {} self.bin_path = get_nsb_option('bin_path', '') + self._mq_ids = [] def _get_ip_flow_range(self, ip_start_range): + """Retrieve a CIDR first and last viable IPs - # IP range is specified as 'x.x.x.x-y.y.y.y' + :param ip_start_range: could be the IP range itself or a dictionary + with the host name and the port. + :return: (str) IP range (min, max) with this format "x.x.x.x-y.y.y.y" + """ if isinstance(ip_start_range, six.string_types): return ip_start_range - node_name, range_or_interface = next(iter(ip_start_range.items()), (None, '0.0.0.0')) + node_name, range_or_interface = next(iter(ip_start_range.items()), + (None, '0.0.0.0')) if node_name is None: - # we are manually specifying the range - ip_addr_range = range_or_interface + return range_or_interface + + node = self.context_cfg['nodes'].get(node_name, {}) + interface = node.get('interfaces', {}).get(range_or_interface) + if interface: + ip = interface['local_ip'] + mask = interface['netmask'] else: - node = self.context_cfg["nodes"].get(node_name, {}) - try: - # the ip_range is the interface name - interface = node.get("interfaces", {})[range_or_interface] - except KeyError: - ip = "0.0.0.0" - mask = "255.255.255.0" - else: - ip = interface["local_ip"] - # we can't default these values, they must both exist to be valid - mask = interface["netmask"] - - ipaddr = ipaddress.ip_network(six.text_type('{}/{}'.format(ip, mask)), strict=False) - hosts = list(ipaddr.hosts()) - if len(hosts) > 2: - # skip the first host in case of gateway - ip_addr_range = "{}-{}".format(hosts[1], hosts[-1]) - else: - LOG.warning("Only single IP in range %s", ipaddr) - # fall back to single IP range - ip_addr_range = ip + ip = '0.0.0.0' + mask = '255.255.255.0' + + ipaddr = ipaddress.ip_network( + six.text_type('{}/{}'.format(ip, mask)), strict=False) + if ipaddr.prefixlen + 2 < ipaddr.max_prefixlen: + ip_addr_range = '{}-{}'.format(ipaddr[2], ipaddr[-2]) + else: + LOG.warning('Only single IP in range %s', ipaddr) + ip_addr_range = ip return ip_addr_range def _get_traffic_flow(self): @@ -117,6 +118,7 @@ class NetworkServiceTestCase(scenario_base.Scenario): flow["dst_port_{}".format(index)] = dst_port flow["count"] = fflow["count"] + flow["seed"] = fflow["seed"] except KeyError: flow = {} return {"flow": flow} @@ -134,11 +136,10 @@ class NetworkServiceTestCase(scenario_base.Scenario): with utils.open_relative_file(profile, path) as infile: return infile.read() - def _get_topology(self): - topology = self.scenario_cfg["topology"] - path = self.scenario_cfg["task_path"] - with utils.open_relative_file(topology, path) as infile: - return infile.read() + def _get_duration(self): + options = self.scenario_cfg.get('options', {}) + return options.get('duration', + tprofile_base.TrafficProfileConfig.DEFAULT_DURATION) def _fill_traffic_profile(self): tprofile = self._get_traffic_profile() @@ -148,12 +149,17 @@ class NetworkServiceTestCase(scenario_base.Scenario): 'imix': self._get_traffic_imix(), tprofile_base.TrafficProfile.UPLINK: {}, tprofile_base.TrafficProfile.DOWNLINK: {}, - 'extra_args': extra_args - } - + 'extra_args': extra_args, + 'duration': self._get_duration()} traffic_vnfd = vnfdgen.generate_vnfd(tprofile, tprofile_data) self.traffic_profile = tprofile_base.TrafficProfile.get(traffic_vnfd) + def _get_topology(self): + topology = self.scenario_cfg["topology"] + path = self.scenario_cfg["task_path"] + with utils.open_relative_file(topology, path) as infile: + return infile.read() + def _render_topology(self): topology = self._get_topology() topology_args = self.scenario_cfg.get('extra_args', {}) @@ -163,18 +169,18 @@ class NetworkServiceTestCase(scenario_base.Scenario): topology_yaml = vnfdgen.generate_vnfd(topology, topolgy_data) self.topology = topology_yaml["nsd:nsd-catalog"]["nsd"][0] - def _find_vnf_name_from_id(self, vnf_id): + def _find_vnf_name_from_id(self, vnf_id): # pragma: no cover return next((vnfd["vnfd-id-ref"] for vnfd in self.topology["constituent-vnfd"] if vnf_id == vnfd["member-vnf-index"]), None) - def _find_vnfd_from_vnf_idx(self, vnf_id): + def _find_vnfd_from_vnf_idx(self, vnf_id): # pragma: no cover return next((vnfd for vnfd in self.topology["constituent-vnfd"] if vnf_id == vnfd["member-vnf-index"]), None) @staticmethod - def find_node_if(nodes, name, if_name, vld_id): + def find_node_if(nodes, name, if_name, vld_id): # pragma: no cover try: # check for xe0, xe1 intf = nodes[name]["interfaces"][if_name] @@ -190,8 +196,9 @@ class NetworkServiceTestCase(scenario_base.Scenario): try: node0_data, node1_data = vld["vnfd-connection-point-ref"] except (ValueError, TypeError): - raise IncorrectConfig("Topology file corrupted, " - "wrong endpoint count for connection") + raise exceptions.IncorrectConfig( + error_msg='Topology file corrupted, wrong endpoint count ' + 'for connection') node0_name = self._find_vnf_name_from_id(node0_data["member-vnf-index-ref"]) node1_name = self._find_vnf_name_from_id(node1_data["member-vnf-index-ref"]) @@ -237,15 +244,17 @@ class NetworkServiceTestCase(scenario_base.Scenario): except KeyError: LOG.exception("") - raise IncorrectConfig("Required interface not found, " - "topology file corrupted") + raise exceptions.IncorrectConfig( + error_msg='Required interface not found, topology file ' + 'corrupted') for vld in self.topology['vld']: try: node0_data, node1_data = vld["vnfd-connection-point-ref"] except (ValueError, TypeError): - raise IncorrectConfig("Topology file corrupted, " - "wrong endpoint count for connection") + raise exceptions.IncorrectConfig( + error_msg='Topology file corrupted, wrong endpoint count ' + 'for connection') node0_name = self._find_vnf_name_from_id(node0_data["member-vnf-index-ref"]) node1_name = self._find_vnf_name_from_id(node1_data["member-vnf-index-ref"]) @@ -264,14 +273,14 @@ class NetworkServiceTestCase(scenario_base.Scenario): node0_if["peer_intf"] = node1_copy node1_if["peer_intf"] = node0_copy - def _update_context_with_topology(self): + def _update_context_with_topology(self): # pragma: no cover for vnfd in self.topology["constituent-vnfd"]: vnf_idx = vnfd["member-vnf-index"] vnf_name = self._find_vnf_name_from_id(vnf_idx) vnfd = self._find_vnfd_from_vnf_idx(vnf_idx) self.context_cfg["nodes"][vnf_name].update(vnfd) - def _generate_pod_yaml(self): + def _generate_pod_yaml(self): # pragma: no cover context_yaml = os.path.join(LOG_DIR, "pod-{}.yaml".format(self.scenario_cfg['task_id'])) # convert OrderedDict to a list # pod.yaml nodes is a list @@ -285,7 +294,7 @@ class NetworkServiceTestCase(scenario_base.Scenario): explicit_start=True) @staticmethod - def _serialize_node(node): + def _serialize_node(node): # pragma: no cover new_node = copy.deepcopy(node) # name field is required # remove context suffix @@ -307,7 +316,7 @@ class NetworkServiceTestCase(scenario_base.Scenario): self._update_context_with_topology() @classmethod - def get_vnf_impl(cls, vnf_model_id): + def get_vnf_impl(cls, vnf_model_id): # pragma: no cover """ Find the implementing class from vnf_model["vnf"]["name"] field :param vnf_model_id: parsed vnfd model ID field @@ -330,11 +339,12 @@ class NetworkServiceTestCase(scenario_base.Scenario): except StopIteration: pass - raise IncorrectConfig("No implementation for %s found in %s" % - (expected_name, classes_found)) + message = ('No implementation for %s found in %s' + % (expected_name, classes_found)) + raise exceptions.IncorrectConfig(error_msg=message) @staticmethod - def create_interfaces_from_node(vnfd, node): + def create_interfaces_from_node(vnfd, node): # pragma: no cover ext_intfs = vnfd["vdu"][0]["external-interface"] = [] # have to sort so xe0 goes first for intf_name, intf in sorted(node['interfaces'].items()): @@ -396,17 +406,14 @@ class NetworkServiceTestCase(scenario_base.Scenario): pass self.create_interfaces_from_node(vnfd, node) vnf_impl = self.get_vnf_impl(vnfd['id']) - vnf_instance = vnf_impl(node_name, vnfd) + vnf_instance = vnf_impl(node_name, vnfd, scenario_cfg['task_id']) vnfs.append(vnf_instance) self.vnfs = vnfs return vnfs def setup(self): - """ Setup infrastructure, provission VNFs & start traffic - - :return: - """ + """Setup infrastructure, provission VNFs & start traffic""" # 1. Verify if infrastructure mapping can meet topology self.map_topology_to_infrastructure() # 1a. Load VNF models @@ -441,13 +448,18 @@ class NetworkServiceTestCase(scenario_base.Scenario): traffic_gen.listen_traffic(self.traffic_profile) # register collector with yardstick for KPI collection. - self.collector = Collector(self.vnfs) + self.collector = Collector(self.vnfs, context_base.Context.get_physical_nodes()) self.collector.start() # Start the actual traffic for traffic_gen in traffic_runners: LOG.info("Starting traffic on %s", traffic_gen.name) traffic_gen.run_traffic(self.traffic_profile) + self._mq_ids.append(traffic_gen.get_mq_producer_id()) + + def get_mq_ids(self): # pragma: no cover + """Return stored MQ producer IDs""" + return self._mq_ids def run(self, result): # yardstick API """ Yardstick calls run() at intervals defined in the yaml and @@ -486,10 +498,10 @@ class NetworkServiceTestCase(scenario_base.Scenario): LOG.exception("") raise RuntimeError("Error in teardown") - def pre_run_wait_time(self, time_seconds): + def pre_run_wait_time(self, time_seconds): # pragma: no cover """Time waited before executing the run method""" time.sleep(time_seconds) - def post_run_wait_time(self, time_seconds): + def post_run_wait_time(self, time_seconds): # pragma: no cover """Time waited after executing the run method""" pass diff --git a/yardstick/benchmark/scenarios/networking/vsperf.py b/yardstick/benchmark/scenarios/networking/vsperf.py index 705544c41..8344b1595 100644 --- a/yardstick/benchmark/scenarios/networking/vsperf.py +++ b/yardstick/benchmark/scenarios/networking/vsperf.py @@ -193,37 +193,34 @@ class Vsperf(base.Scenario): cmd += "--conf-file ~/vsperf.conf " cmd += "--test-params=\"%s\"" % (';'.join(test_params)) LOG.debug("Executing command: %s", cmd) - status, stdout, stderr = self.client.execute(cmd) - - if status: - raise RuntimeError(stderr) + self.client.run(cmd) # get test results cmd = "cat /tmp/results*/result.csv" LOG.debug("Executing command: %s", cmd) - status, stdout, stderr = self.client.execute(cmd) - - if status: - raise RuntimeError(stderr) + _, stdout, _ = self.client.execute(cmd, raise_on_error=True) # convert result.csv to JSON format - reader = csv.DictReader(stdout.split('\r\n')) - result.update(next(reader)) + reader = csv.DictReader(stdout.split('\r\n'), strict=True) + try: + result.update(next(reader)) + except StopIteration: + pass # sla check; go through all defined SLAs and check if values measured # by VSPERF are higher then those defined by SLAs if 'sla' in self.scenario_cfg and \ 'metrics' in self.scenario_cfg['sla']: for metric in self.scenario_cfg['sla']['metrics'].split(','): - assert metric in result, \ - '%s is not collected by VSPERF' % (metric) - assert metric in self.scenario_cfg['sla'], \ - '%s is not defined in SLA' % (metric) + self.verify_SLA(metric in result, + '%s was not collected by VSPERF' % metric) + self.verify_SLA(metric in self.scenario_cfg['sla'], + '%s is not defined in SLA' % metric) vs_res = float(result[metric]) sla_res = float(self.scenario_cfg['sla'][metric]) - assert vs_res >= sla_res, \ - 'VSPERF_%s(%f) < SLA_%s(%f)' % \ - (metric, vs_res, metric, sla_res) + self.verify_SLA(vs_res >= sla_res, + 'VSPERF_%s(%f) < SLA_%s(%f)' + % (metric, vs_res, metric, sla_res)) def teardown(self): """cleanup after the test execution""" diff --git a/yardstick/benchmark/scenarios/networking/vsperf_dpdk.py b/yardstick/benchmark/scenarios/networking/vsperf_dpdk.py index 454587829..d5c8a3bfe 100644 --- a/yardstick/benchmark/scenarios/networking/vsperf_dpdk.py +++ b/yardstick/benchmark/scenarios/networking/vsperf_dpdk.py @@ -205,22 +205,17 @@ class VsperfDPDK(base.Scenario): self.client.send_command(cmd) else: cmd = "cat ~/.testpmd.macaddr.port1" - status, stdout, stderr = self.client.execute(cmd) - if status: - raise RuntimeError(stderr) + _, stdout, _ = self.client.execute(cmd, raise_on_error=True) self.tgen_port1_mac = stdout + cmd = "cat ~/.testpmd.macaddr.port2" - status, stdout, stderr = self.client.execute(cmd) - if status: - raise RuntimeError(stderr) + _, stdout, _ = self.client.execute(cmd, raise_on_error=True) self.tgen_port2_mac = stdout cmd = "screen -d -m sudo -E bash ~/testpmd_vsperf.sh %s %s" % \ (self.moongen_port1_mac, self.moongen_port2_mac) LOG.debug("Executing command: %s", cmd) - status, stdout, stderr = self.client.execute(cmd) - if status: - raise RuntimeError(stderr) + self.client.run(cmd) time.sleep(1) @@ -231,7 +226,7 @@ class VsperfDPDK(base.Scenario): is_run = True cmd = "ip a | grep %s 2>/dev/null" % (self.tg_port1) LOG.debug("Executing command: %s", cmd) - status, stdout, stderr = self.client.execute(cmd) + _, stdout, _ = self.client.execute(cmd) if stdout: is_run = False return is_run @@ -245,7 +240,7 @@ class VsperfDPDK(base.Scenario): self.setup() # remove results from previous tests - self.client.execute("rm -rf /tmp/results*") + self.client.run("rm -rf /tmp/results*", raise_on_error=False) # get vsperf options options = self.scenario_cfg['options'] @@ -291,9 +286,7 @@ class VsperfDPDK(base.Scenario): cmd = "sshpass -p yardstick ssh-copy-id -o StrictHostKeyChecking=no " \ "root@%s -p 22" % (self.moongen_host_ip) LOG.debug("Executing command: %s", cmd) - status, stdout, stderr = self.client.execute(cmd) - if status: - raise RuntimeError(stderr) + self.client.run(cmd) # execute vsperf cmd = "source ~/vsperfenv/bin/activate ; cd vswitchperf ; " @@ -302,22 +295,19 @@ class VsperfDPDK(base.Scenario): cmd += "--conf-file ~/vsperf.conf " cmd += "--test-params=\"%s\"" % (';'.join(test_params)) LOG.debug("Executing command: %s", cmd) - status, stdout, stderr = self.client.execute(cmd) - - if status: - raise RuntimeError(stderr) + self.client.run(cmd) # get test results cmd = "cat /tmp/results*/result.csv" LOG.debug("Executing command: %s", cmd) - status, stdout, stderr = self.client.execute(cmd) - - if status: - raise RuntimeError(stderr) + _, stdout, _ = self.client.execute(cmd, raise_on_error=True) # convert result.csv to JSON format reader = csv.DictReader(stdout.split('\r\n')) - result.update(next(reader)) + try: + result.update(next(reader)) + except StopIteration: + pass result['nrFlows'] = multistream # sla check; go through all defined SLAs and check if values measured @@ -325,15 +315,15 @@ class VsperfDPDK(base.Scenario): if 'sla' in self.scenario_cfg and \ 'metrics' in self.scenario_cfg['sla']: for metric in self.scenario_cfg['sla']['metrics'].split(','): - assert metric in result, \ - '%s is not collected by VSPERF' % (metric) - assert metric in self.scenario_cfg['sla'], \ - '%s is not defined in SLA' % (metric) + self.verify_SLA(metric in result, + '%s was not collected by VSPERF' % metric) + self.verify_SLA(metric in self.scenario_cfg['sla'], + '%s is not defined in SLA' % metric) vs_res = float(result[metric]) sla_res = float(self.scenario_cfg['sla'][metric]) - assert vs_res >= sla_res, \ - 'VSPERF_%s(%f) < SLA_%s(%f)' % \ - (metric, vs_res, metric, sla_res) + self.verify_SLA(vs_res >= sla_res, + 'VSPERF_%s(%f) < SLA_%s(%f)' + % (metric, vs_res, metric, sla_res)) def teardown(self): """cleanup after the test execution""" diff --git a/yardstick/benchmark/scenarios/storage/fio.py b/yardstick/benchmark/scenarios/storage/fio.py index d3ed840d8..c57c6edf2 100644 --- a/yardstick/benchmark/scenarios/storage/fio.py +++ b/yardstick/benchmark/scenarios/storage/fio.py @@ -223,7 +223,7 @@ class Fio(base.Scenario): sla_error += "%s %d < " \ "sla:%s(%d); " % (k, v, k, min_v) - assert sla_error == "", sla_error + self.verify_SLA(sla_error == "", sla_error) def _test(): diff --git a/yardstick/common/ansible_common.py b/yardstick/common/ansible_common.py index ca5a110e2..dee7044a5 100644 --- a/yardstick/common/ansible_common.py +++ b/yardstick/common/ansible_common.py @@ -12,8 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from __future__ import absolute_import - import cgitb import collections import contextlib as cl @@ -23,11 +21,11 @@ import os from collections import Mapping, MutableMapping, Iterable, Callable, deque from functools import partial from itertools import chain -from subprocess import CalledProcessError, Popen, PIPE -from tempfile import NamedTemporaryFile +import subprocess +import tempfile import six -import six.moves.configparser as ConfigParser +from six.moves import configparser import yaml from six import StringIO from chainmap import ChainMap @@ -134,10 +132,9 @@ class CustomTemporaryFile(object): else: self.data_types = self.DEFAULT_DATA_TYPES # must open "w+" so unicode is encoded correctly - self.creator = partial(NamedTemporaryFile, mode="w+", delete=False, - dir=directory, - prefix=prefix, - suffix=self.suffix) + self.creator = partial( + tempfile.NamedTemporaryFile, mode="w+", delete=False, + dir=directory, prefix=prefix, suffix=self.suffix) def make_context(self, data, write_func, descriptor='data'): return TempfileContext(data, write_func, descriptor, self.data_types, @@ -191,8 +188,8 @@ class FileNameGenerator(object): if not prefix.endswith('_'): prefix += '_' - temp_file = NamedTemporaryFile(delete=False, dir=directory, - prefix=prefix, suffix=suffix) + temp_file = tempfile.NamedTemporaryFile(delete=False, dir=directory, + prefix=prefix, suffix=suffix) with cl.closing(temp_file): return temp_file.name @@ -474,7 +471,7 @@ class AnsibleCommon(object): prefix = '_'.join([self.prefix, prefix, 'inventory']) ini_temp_file = IniMapTemporaryFile(directory=directory, prefix=prefix) - inventory_config = ConfigParser.ConfigParser(allow_no_value=True) + inventory_config = configparser.ConfigParser(allow_no_value=True) # disable default lowercasing inventory_config.optionxform = str return ini_temp_file.make_context(self.inventory_dict, write_func, @@ -510,7 +507,7 @@ class AnsibleCommon(object): return timeout def _generate_ansible_cfg(self, directory): - parser = ConfigParser.ConfigParser() + parser = configparser.ConfigParser() parser.add_section('defaults') parser.set('defaults', 'host_key_checking', 'False') @@ -541,12 +538,12 @@ class AnsibleCommon(object): cmd = ['ansible', 'all', '-m', 'setup', '-i', inventory_path, '--tree', sut_dir] - proc = Popen(cmd, stdout=PIPE, cwd=directory) + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, cwd=directory) output, _ = proc.communicate() retcode = proc.wait() LOG.debug("exit status = %s", retcode) if retcode != 0: - raise CalledProcessError(retcode, cmd, output) + raise subprocess.CalledProcessError(retcode, cmd, output) def _gen_sut_info_dict(self, sut_dir): sut_info = {} @@ -617,12 +614,13 @@ class AnsibleCommon(object): # 'timeout': timeout / 2, }) with Timer() as timer: - proc = Popen(cmd, stdout=PIPE, **exec_args) + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, + **exec_args) output, _ = proc.communicate() retcode = proc.wait() LOG.debug("exit status = %s", retcode) if retcode != 0: - raise CalledProcessError(retcode, cmd, output) + raise subprocess.CalledProcessError(retcode, cmd, output) timeout -= timer.total_seconds() cmd.remove("--syntax-check") @@ -632,10 +630,10 @@ class AnsibleCommon(object): # TODO: add timeout support of use subprocess32 backport # 'timeout': timeout, }) - proc = Popen(cmd, stdout=PIPE, **exec_args) + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, **exec_args) output, _ = proc.communicate() retcode = proc.wait() LOG.debug("exit status = %s", retcode) if retcode != 0: - raise CalledProcessError(retcode, cmd, output) + raise subprocess.CalledProcessError(retcode, cmd, output) return output diff --git a/yardstick/common/constants.py b/yardstick/common/constants.py index 8640afbae..3d775d48e 100644 --- a/yardstick/common/constants.py +++ b/yardstick/common/constants.py @@ -6,7 +6,6 @@ # which accompanies this distribution, and is available at # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -from __future__ import absolute_import import errno import os @@ -14,11 +13,9 @@ from functools import reduce import pkg_resources -# this module must only import other modules that do -# not require loggers to be created, so this cannot -# include yardstick.common.utils from yardstick.common.yaml_loader import yaml_load + dirname = os.path.dirname abspath = os.path.abspath join = os.path.join @@ -119,6 +116,7 @@ INFLUXDB_DB_NAME = get_param('influxdb.db_name', 'yardstick') INFLUXDB_IMAGE = get_param('influxdb.image', 'tutum/influxdb') INFLUXDB_TAG = get_param('influxdb.tag', '0.13') INFLUXDB_DASHBOARD_PORT = 8083 +QUEUE_PUT_TIMEOUT = 10 # grafana GRAFANA_IP = get_param('grafana.ip', SERVER_IP) @@ -145,6 +143,21 @@ BASE_URL = 'http://localhost:5000' ENV_ACTION_API = BASE_URL + '/yardstick/env/action' ASYNC_TASK_API = BASE_URL + '/yardstick/asynctask' +API_ERRORS = { + 'UploadOpenrcError': { + 'message': "Upload openrc ERROR!", + 'status': API_ERROR, + }, + 'UpdateOpenrcError': { + 'message': "Update openrc ERROR!", + 'status': API_ERROR, + }, + 'ApiServerError': { + 'message': "An unkown exception happened to Api Server!", + 'status': API_ERROR, + }, +} + # flags IS_EXISTING = 'is_existing' IS_PUBLIC = 'is_public' @@ -155,3 +168,11 @@ TESTSUITE_PRE = 'opnfv_' # OpenStack cloud default config parameters OS_CLOUD_DEFAULT_CONFIG = {'verify': False} + +# Kubernetes +SCOPE_NAMESPACED = 'Namespaced' +SCOPE_CLUSTER = 'Cluster' + +# VNF definition +SSH_PORT = 22 +LUA_PORT = 22022 diff --git a/yardstick/common/exceptions.py b/yardstick/common/exceptions.py index 36c7eef05..9fbe19949 100644 --- a/yardstick/common/exceptions.py +++ b/yardstick/common/exceptions.py @@ -14,6 +14,8 @@ from oslo_utils import excutils +from yardstick.common import constants + class ProcessExecutionError(RuntimeError): def __init__(self, message, returncode): @@ -21,6 +23,16 @@ class ProcessExecutionError(RuntimeError): self.returncode = returncode +class ErrorClass(object): + + def __init__(self, *args, **kwargs): + if 'test' not in kwargs: + raise RuntimeError + + def __getattr__(self, item): + raise AttributeError + + class YardstickException(Exception): """Base Yardstick Exception. @@ -58,23 +70,34 @@ class ResourceCommandError(YardstickException): message = 'Command: "%(command)s" Failed, stderr: "%(stderr)s"' +class ContextUpdateCollectdForNodeError(YardstickException): + message = 'Cannot find node %(attr_name)s' + + class FunctionNotImplemented(YardstickException): message = ('The function "%(function_name)s" is not implemented in ' '"%(class_name)" class.') +class InfluxDBConfigurationMissing(YardstickException): + message = ('InfluxDB configuration is not available. Add "influxdb" as ' + 'a dispatcher and the configuration section') + + class YardstickBannedModuleImported(YardstickException): - # pragma: no cover message = 'Module "%(module)s" cannnot be imported. Reason: "%(reason)s"' +class IXIAUnsupportedProtocol(YardstickException): + message = 'Protocol "%(protocol)" is not supported in IXIA' + + class PayloadMissingAttributes(YardstickException): message = ('Error instantiating a Payload class, missing attributes: ' '%(missing_attributes)s') class HeatTemplateError(YardstickException): - """Error in Heat during the stack deployment""" message = ('Error in Heat during the creation of the OpenStack stack ' '"%(stack_name)s"') @@ -87,6 +110,10 @@ class TrafficProfileNotImplemented(YardstickException): message = 'No implementation for traffic profile %(profile_class)s.' +class TrafficProfileRate(YardstickException): + message = 'Traffic profile rate must be "<number>[fps|%]"' + + class DPDKSetupDriverError(YardstickException): message = '"igb_uio" driver is not loaded' @@ -132,8 +159,28 @@ class LibvirtQemuImageCreateError(YardstickException): '%(base_image)s. Error: %(error)s.') +class SSHError(YardstickException): + message = '%(error_msg)s' + + +class SSHTimeout(SSHError): + pass + + +class IncorrectConfig(YardstickException): + message = '%(error_msg)s' + + +class IncorrectSetup(YardstickException): + message = '%(error_msg)s' + + +class IncorrectNodeSetup(IncorrectSetup): + pass + + class ScenarioConfigContextNameNotFound(YardstickException): - message = 'Context name "%(context_name)s" not found' + message = 'Context for host name "%(host_name)s" not found' class StackCreationInterrupt(YardstickException): @@ -152,6 +199,15 @@ class TaskRenderError(YardstickException): message = 'Failed to render template:\n%(input_task)s' +class RunnerIterationIPCSetupActionNeeded(YardstickException): + message = ('IterationIPC needs the "setup" action to retrieve the VNF ' + 'handling processes PIDs to receive the messages sent') + + +class RunnerIterationIPCNoCtxs(YardstickException): + message = 'Benchmark "setup" action did not return any VNF process PID' + + class TimerTimeout(YardstickException): message = 'Timer timeout expired, %(timeout)s seconds' @@ -160,6 +216,71 @@ class WaitTimeout(YardstickException): message = 'Wait timeout while waiting for condition' +class PktgenActionError(YardstickException): + message = 'Error in "%(action)s" action' + + +class KubernetesApiException(YardstickException): + message = ('Kubernetes API errors. Action: %(action)s, ' + 'resource: %(resource)s') + + +class KubernetesConfigFileNotFound(YardstickException): + message = 'Config file (%s) not found' % constants.K8S_CONF_FILE + + +class KubernetesTemplateInvalidVolumeType(YardstickException): + message = 'No valid "volume" types present in %(volume)s' + + +class KubernetesSSHPortNotDefined(YardstickException): + message = 'Port 22 needs to be defined' + + +class KubernetesServiceObjectNotDefined(YardstickException): + message = 'ServiceObject is not defined' + + +class KubernetesServiceObjectDefinitionError(YardstickException): + message = ('Kubernetes Service object definition error, missing ' + 'parameters: %(missing_parameters)s') + + +class KubernetesServiceObjectNameError(YardstickException): + message = ('Kubernetes Service object name "%(name)s" does not comply' + 'naming convention') + + +class KubernetesCRDObjectDefinitionError(YardstickException): + message = ('Kubernetes Custom Resource Definition Object error, missing ' + 'parameters: %(missing_parameters)s') + + +class KubernetesNetworkObjectDefinitionError(YardstickException): + message = ('Kubernetes Network object definition error, missing ' + 'parameters: %(missing_parameters)s') + + +class KubernetesNetworkObjectKindMissing(YardstickException): + message = 'Kubernetes kind "Network" is not defined' + + +class KubernetesWrongRestartPolicy(YardstickException): + message = 'Restart policy "%(rpolicy)s" is not valid' + + +class KubernetesContainerPortNotDefined(YardstickException): + message = 'Container port not defined in "%(port)s"' + + +class KubernetesContainerWrongImagePullPolicy(YardstickException): + message = 'Image pull policy must be "Always", "IfNotPresent" or "Never"' + + +class KubernetesContainerCommandType(YardstickException): + message = '"args" and "command" must be string or list of strings' + + class ScenarioCreateNetworkError(YardstickException): message = 'Create Neutron Network Scenario failed' @@ -242,3 +363,52 @@ class ScenarioDeleteVolumeError(YardstickException): class ScenarioDetachVolumeError(YardstickException): message = 'Cinder Detach Volume Scenario failed' + + +class ApiServerError(YardstickException): + message = 'An unkown exception happened to Api Server!' + + +class UploadOpenrcError(ApiServerError): + message = 'Upload openrc ERROR!' + + +class UpdateOpenrcError(ApiServerError): + message = 'Update openrc ERROR!' + + +class ScenarioCreateImageError(YardstickException): + message = 'Glance Create Image Scenario failed' + + +class ScenarioDeleteImageError(YardstickException): + message = 'Glance Delete Image Scenario failed' + + +class IxNetworkClientNotConnected(YardstickException): + message = 'IxNetwork client not connected to a TCL server' + + +class IxNetworkFlowNotPresent(YardstickException): + message = 'Flow Group "%(flow_group)s" is not present' + + +class IxNetworkFieldNotPresentInStackItem(YardstickException): + message = 'Field "%(field_name)s" not present in stack item %(stack_item)s' + + +class SLAValidationError(YardstickException): + message = '%(case_name)s SLA validation failed. Error: %(error_msg)s' + + +class AclMissingActionArguments(YardstickException): + message = ('Missing ACL action parameter ' + '[action=%(action_name)s parameter=%(action_param)s]') + + +class AclUnknownActionTemplate(YardstickException): + message = 'No ACL CLI template found for "%(action_name)s" action' + + +class InvalidMacAddress(YardstickException): + message = 'Mac address "%(mac_address)s" is invalid' diff --git a/yardstick/common/httpClient.py b/yardstick/common/httpClient.py index 54f7be670..5b7831144 100644 --- a/yardstick/common/httpClient.py +++ b/yardstick/common/httpClient.py @@ -26,10 +26,11 @@ class HttpClient(object): while True: try: response = requests.post(url, data=data, headers=headers) + response.raise_for_status() result = response.json() logger.debug('The result is: %s', result) return result - except Exception: + except Exception: # pylint: disable=broad-except if time.time() > t_end: logger.exception('') raise @@ -37,4 +38,5 @@ class HttpClient(object): def get(self, url): response = requests.get(url) + response.raise_for_status() return response.json() diff --git a/yardstick/common/kubernetes_utils.py b/yardstick/common/kubernetes_utils.py index 0cf7b9eab..323f13abb 100644 --- a/yardstick/common/kubernetes_utils.py +++ b/yardstick/common/kubernetes_utils.py @@ -13,6 +13,8 @@ from kubernetes import config from kubernetes.client.rest import ApiException from yardstick.common import constants as consts +from yardstick.common import exceptions + LOG = logging.getLogger(__name__) LOG.setLevel(logging.DEBUG) @@ -22,12 +24,26 @@ def get_core_api(): # pragma: no cover try: config.load_kube_config(config_file=consts.K8S_CONF_FILE) except IOError: - LOG.exception('config file not found') - raise - + raise exceptions.KubernetesConfigFileNotFound() return client.CoreV1Api() +def get_extensions_v1beta_api(): + try: + config.load_kube_config(config_file=consts.K8S_CONF_FILE) + except IOError: + raise exceptions.KubernetesConfigFileNotFound() + return client.ApiextensionsV1beta1Api() + + +def get_custom_objects_api(): + try: + config.load_kube_config(config_file=consts.K8S_CONF_FILE) + except IOError: + raise exceptions.KubernetesConfigFileNotFound() + return client.CustomObjectsApi() + + def get_node_list(**kwargs): # pragma: no cover core_v1_api = get_core_api() try: @@ -41,6 +57,7 @@ def create_service(template, namespace='default', wait=False, **kwargs): # pragma: no cover + # pylint: disable=unused-argument core_v1_api = get_core_api() metadata = client.V1ObjectMeta(**template.get('metadata', {})) @@ -58,14 +75,18 @@ def create_service(template, raise -def delete_service(name, - namespace='default', - **kwargs): # pragma: no cover +def delete_service(name, namespace='default', skip_codes=None, **kwargs): + skip_codes = [] if not skip_codes else skip_codes core_v1_api = get_core_api() try: - core_v1_api.delete_namespaced_service(name, namespace, **kwargs) - except ApiException: - LOG.exception('Delete Service failed') + body = client.V1DeleteOptions() + core_v1_api.delete_namespaced_service(name, namespace, body, **kwargs) + except ApiException as e: + if e.status in skip_codes: + LOG.info(e.reason) + else: + raise exceptions.KubernetesApiException( + action='delete', resource='Service') def get_service_list(namespace='default', **kwargs): @@ -86,7 +107,7 @@ def create_replication_controller(template, namespace='default', wait=False, **kwargs): # pragma: no cover - + # pylint: disable=unused-argument core_v1_api = get_core_api() try: core_v1_api.create_namespaced_replication_controller(namespace, @@ -100,8 +121,10 @@ def create_replication_controller(template, def delete_replication_controller(name, namespace='default', wait=False, - **kwargs): # pragma: no cover - + skip_codes=None, + **kwargs): + # pylint: disable=unused-argument + skip_codes = [] if not skip_codes else skip_codes core_v1_api = get_core_api() body = kwargs.get('body', client.V1DeleteOptions()) kwargs.pop('body', None) @@ -110,16 +133,21 @@ def delete_replication_controller(name, namespace, body, **kwargs) - except ApiException: - LOG.exception('Delete replication controller failed') - raise + except ApiException as e: + if e.status in skip_codes: + LOG.info(e.reason) + else: + raise exceptions.KubernetesApiException( + action='delete', resource='ReplicationController') def delete_pod(name, namespace='default', wait=False, + skip_codes=None, **kwargs): # pragma: no cover - + # pylint: disable=unused-argument + skip_codes = [] if not skip_codes else skip_codes core_v1_api = get_core_api() body = kwargs.get('body', client.V1DeleteOptions()) kwargs.pop('body', None) @@ -128,9 +156,12 @@ def delete_pod(name, namespace, body, **kwargs) - except ApiException: - LOG.exception('Delete pod failed') - raise + except ApiException as e: + if e.status in skip_codes: + LOG.info(e.reason) + else: + raise exceptions.KubernetesApiException( + action='delete', resource='Pod') def read_pod(name, @@ -147,6 +178,7 @@ def read_pod(name, def read_pod_status(name, namespace='default', **kwargs): # pragma: no cover + # pylint: disable=unused-argument return read_pod(name).status.phase @@ -155,6 +187,7 @@ def create_config_map(name, namespace='default', wait=False, **kwargs): # pragma: no cover + # pylint: disable=unused-argument core_v1_api = get_core_api() metadata = client.V1ObjectMeta(name=name) body = client.V1ConfigMap(data=data, metadata=metadata) @@ -168,7 +201,10 @@ def create_config_map(name, def delete_config_map(name, namespace='default', wait=False, - **kwargs): # pragma: no cover + skip_codes=None, + **kwargs): + # pylint: disable=unused-argument + skip_codes = [] if not skip_codes else skip_codes core_v1_api = get_core_api() body = kwargs.get('body', client.V1DeleteOptions()) kwargs.pop('body', None) @@ -177,9 +213,104 @@ def delete_config_map(name, namespace, body, **kwargs) + except ApiException as e: + if e.status in skip_codes: + LOG.info(e.reason) + else: + raise exceptions.KubernetesApiException( + action='delete', resource='ConfigMap') + + +def create_custom_resource_definition(body): + api = get_extensions_v1beta_api() + body_obj = client.V1beta1CustomResourceDefinition( + spec=body['spec'], metadata=body['metadata']) + try: + api.create_custom_resource_definition(body_obj) + except ValueError: + # NOTE(ralonsoh): bug in kubernetes-client/python 6.0.0 + # https://github.com/kubernetes-client/python/issues/491 + pass except ApiException: - LOG.exception('Delete config map failed') - raise + raise exceptions.KubernetesApiException( + action='create', resource='CustomResourceDefinition') + + +def delete_custom_resource_definition(name, skip_codes=None): + skip_codes = [] if not skip_codes else skip_codes + api = get_extensions_v1beta_api() + body_obj = client.V1DeleteOptions() + try: + api.delete_custom_resource_definition(name, body_obj) + except ApiException as e: + if e.status in skip_codes: + LOG.info(e.reason) + else: + raise exceptions.KubernetesApiException( + action='delete', resource='CustomResourceDefinition') + + +def get_custom_resource_definition(kind): + api = get_extensions_v1beta_api() + try: + crd_list = api.list_custom_resource_definition() + for crd_obj in (crd_obj for crd_obj in crd_list.items + if crd_obj.spec.names.kind == kind): + return crd_obj + return None + except ApiException: + raise exceptions.KubernetesApiException( + action='delete', resource='CustomResourceDefinition') + + +def get_network(scope, group, version, plural, name, namespace='default'): + api = get_custom_objects_api() + try: + if scope == consts.SCOPE_CLUSTER: + network = api.get_cluster_custom_object(group, version, plural, name) + else: + network = api.get_namespaced_custom_object( + group, version, namespace, plural, name) + except ApiException as e: + if e.status in [404]: + return + else: + raise exceptions.KubernetesApiException( + action='get', resource='Custom Object: Network') + return network + + +def create_network(scope, group, version, plural, body, name, namespace='default'): + api = get_custom_objects_api() + if get_network(scope, group, version, plural, name, namespace): + logging.info('Network %s already exists', name) + return + try: + if scope == consts.SCOPE_CLUSTER: + api.create_cluster_custom_object(group, version, plural, body) + else: + api.create_namespaced_custom_object( + group, version, namespace, plural, body) + except ApiException: + raise exceptions.KubernetesApiException( + action='create', resource='Custom Object: Network') + + +def delete_network(scope, group, version, plural, name, namespace='default', skip_codes=None): + skip_codes = [] if not skip_codes else skip_codes + api = get_custom_objects_api() + try: + if scope == consts.SCOPE_CLUSTER: + api.delete_cluster_custom_object(group, version, plural, name, {}) + else: + api.delete_namespaced_custom_object( + group, version, namespace, plural, name, {}) + except ApiException as e: + if e.status in skip_codes: + LOG.info(e.reason) + else: + raise exceptions.KubernetesApiException( + action='delete', resource='Custom Object: Network') def get_pod_list(namespace='default'): # pragma: no cover @@ -194,3 +325,9 @@ def get_pod_list(namespace='default'): # pragma: no cover def get_pod_by_name(name): # pragma: no cover pod_list = get_pod_list() return next((n for n in pod_list.items if n.metadata.name.startswith(name)), None) + + +def get_volume_types(): + """Return the "volume" types supported by the current API""" + return [vtype for vtype in client.V1Volume.attribute_map.values() + if vtype != 'name'] diff --git a/yardstick/common/messaging/__init__.py b/yardstick/common/messaging/__init__.py index f0f012ec3..bd700d9b1 100644 --- a/yardstick/common/messaging/__init__.py +++ b/yardstick/common/messaging/__init__.py @@ -1,14 +1,3 @@ -# Copyright (c) 2018 Intel Corporation -# -# 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. @@ -28,9 +17,17 @@ TRANSPORT_URL = (MQ_SERVICE + '://' + MQ_USER + ':' + MQ_PASS + '@' + SERVER + RPC_SERVER_EXECUTOR = 'threading' # Topics. -RUNNER = 'runner' +TOPIC_TG = 'topic_traffic_generator' +TOPIC_RUNNER = 'topic_runner' # Methods. -# RUNNER methods: -RUNNER_INFO = 'runner_info' -RUNNER_LOOP = 'runner_loop' +# Traffic generator consumers methods. Names must match the methods implemented +# in the consumer endpoint class. +TG_METHOD_STARTED = 'tg_method_started' +TG_METHOD_FINISHED = 'tg_method_finished' +TG_METHOD_ITERATION = 'tg_method_iteration' + +# Runner consumers methods. Names must match the methods implemented in the +# consumer endpoint class. +RUNNER_METHOD_START_ITERATION = "runner_method_start_iteration" +RUNNER_METHOD_STOP_ITERATION = "runner_method_stop_iteration" diff --git a/yardstick/common/messaging/consumer.py b/yardstick/common/messaging/consumer.py index 24ec6f184..7ce9bdaf7 100644 --- a/yardstick/common/messaging/consumer.py +++ b/yardstick/common/messaging/consumer.py @@ -29,9 +29,10 @@ LOG = logging.getLogger(__name__) class NotificationHandler(object): """Abstract class to define a endpoint object for a MessagingConsumer""" - def __init__(self, _id, ctx_pids, queue): + def __init__(self, _id, ctx_ids, queue): + super(NotificationHandler, self).__init__() self._id = _id - self._ctx_pids = ctx_pids + self._ctx_ids = ctx_ids self._queue = queue @@ -43,11 +44,11 @@ class MessagingConsumer(object): the messages published by a `MessagingNotifier`. """ - def __init__(self, topic, pids, endpoints, fanout=True): + def __init__(self, topic, ids, endpoints, fanout=True): """Init function. :param topic: (string) MQ exchange topic - :param pids: (list of int) list of PIDs of the processes implementing + :param ids: (list of int) list of IDs of the processes implementing the MQ Notifier which will be in the message context :param endpoints: (list of class) list of classes implementing the methods (see `MessagingNotifier.send_message) used by @@ -58,7 +59,7 @@ class MessagingConsumer(object): :returns: `MessagingConsumer` class object """ - self._pids = pids + self._ids = ids self._endpoints = endpoints self._transport = oslo_messaging.get_rpc_transport( cfg.CONF, url=messaging.TRANSPORT_URL) diff --git a/yardstick/common/messaging/payloads.py b/yardstick/common/messaging/payloads.py index d29d79808..8ede1e58e 100644 --- a/yardstick/common/messaging/payloads.py +++ b/yardstick/common/messaging/payloads.py @@ -51,3 +51,23 @@ class Payload(object): def dict_to_obj(cls, _dict): """Returns a Payload object built from the dictionary elements""" return cls(**_dict) + + +class TrafficGeneratorPayload(Payload): + """Base traffic generator payload class""" + REQUIRED_FIELDS = { + 'version', # (str) version of the payload transmitted. + 'iteration', # (int) iteration index during the traffic injection, + # starting from 1. + 'kpi' # (dict) collection of KPIs collected from the traffic + # injection. The content will depend on the generator and the + # traffic type. + } + + +class RunnerPayload(Payload): + """Base runner payload class""" + REQUIRED_FIELDS = { + 'version', # (str) version of the payload transmitted. + 'data' # (dict) generic container of data to be used if needed. + } diff --git a/yardstick/common/messaging/producer.py b/yardstick/common/messaging/producer.py index b6adc0c17..aadab649d 100644 --- a/yardstick/common/messaging/producer.py +++ b/yardstick/common/messaging/producer.py @@ -34,18 +34,18 @@ class MessagingProducer(object): messages in a message queue. """ - def __init__(self, topic, pid=os.getpid(), fanout=True): + def __init__(self, topic, _id=os.getpid(), fanout=True): """Init function. :param topic: (string) MQ exchange topic - :param pid: (int) PID of the process implementing this MQ Notifier + :param id: (int) ID of the process implementing this MQ Notifier :param fanout: (bool) MQ clients may request that a copy of the message be delivered to all servers listening on a topic by setting fanout to ``True``, rather than just one of them :returns: `MessagingNotifier` class object """ self._topic = topic - self._pid = pid + self._id = _id self._fanout = fanout self._transport = oslo_messaging.get_rpc_transport( cfg.CONF, url=messaging.TRANSPORT_URL) @@ -65,6 +65,11 @@ class MessagingProducer(object): consumer endpoints :param payload: (subclass `Payload`) payload content """ - self._notifier.cast({'pid': self._pid}, + self._notifier.cast({'id': self._id}, method, **payload.obj_to_dict()) + + @property + def id(self): + """Return MQ producer ID""" + return self._id diff --git a/yardstick/common/openstack_utils.py b/yardstick/common/openstack_utils.py index e3e08feb6..541061351 100644 --- a/yardstick/common/openstack_utils.py +++ b/yardstick/common/openstack_utils.py @@ -172,6 +172,15 @@ def get_shade_client(**os_cloud_config): params.update(os_cloud_config) return shade.openstack_cloud(**params) +def get_shade_operator_client(**os_cloud_config): + """Get Shade Operator cloud client + + :return: ``shade.OperatorCloud`` object. + """ + params = copy.deepcopy(constants.OS_CLOUD_DEFAULT_CONFIG) + params.update(os_cloud_config) + return shade.operator_cloud(**params) + # ********************************************* # NOVA @@ -724,48 +733,75 @@ def create_security_group_full(shade_client, sg_name, # ********************************************* # GLANCE # ********************************************* -def get_image_id(glance_client, image_name): # pragma: no cover - images = glance_client.images.list() - return next((i.id for i in images if i.name == image_name), None) - - -def create_image(glance_client, image_name, file_path, disk_format, - container_format, min_disk, min_ram, protected, tag, - public, **kwargs): # pragma: no cover - if not os.path.isfile(file_path): - log.error("Error: file %s does not exist.", file_path) - return None +def create_image(shade_client, name, filename=None, container='images', + md5=None, sha256=None, disk_format=None, + container_format=None, disable_vendor_agent=True, + wait=False, timeout=3600, allow_duplicates=False, meta=None, + volume=None, **kwargs): + """Upload an image. + + :param name:(str) Name of the image to create. If it is a pathname of an + image, the name will be constructed from the extensionless + basename of the path. + :param filename:(str) The path to the file to upload, if needed. + :param container:(str) Name of the container in swift where images should + be uploaded for import if the cloud requires such a thing. + :param md5:(str) md5 sum of the image file. If not given, an md5 will + be calculated. + :param sha256:(str) sha256 sum of the image file. If not given, an md5 + will be calculated. + :param disk_format:(str) The disk format the image is in. + :param container_format:(str) The container format the image is in. + :param disable_vendor_agent:(bool) Whether or not to append metadata + flags to the image to inform the cloud in + question to not expect a vendor agent to be running. + :param wait:(bool) If true, waits for image to be created. + :param timeout:(str) Seconds to wait for image creation. + :param allow_duplicates:(bool) If true, skips checks that enforce unique + image name. + :param meta:(dict) A dict of key/value pairs to use for metadata that + bypasses automatic type conversion. + :param volume:(str) Name or ID or volume object of a volume to create an + image from. + Additional kwargs will be passed to the image creation as additional + metadata for the image and will have all values converted to string + except for min_disk, min_ram, size and virtual_size which will be + converted to int. + If you are sure you have all of your data types correct or have an + advanced need to be explicit, use meta. If you are just a normal + consumer, using kwargs is likely the right choice. + If a value is in meta and kwargs, meta wins. + :returns: Image id + """ try: - image_id = get_image_id(glance_client, image_name) + image_id = shade_client.get_image_id(name) if image_id is not None: - log.info("Image %s already exists.", image_name) - else: - log.info("Creating image '%s' from '%s'...", image_name, file_path) - - image = glance_client.images.create( - name=image_name, visibility=public, disk_format=disk_format, - container_format=container_format, min_disk=min_disk, - min_ram=min_ram, tags=tag, protected=protected, **kwargs) - image_id = image.id - with open(file_path) as image_data: - glance_client.images.upload(image_id, image_data) + log.info("Image %s already exists.", name) + return image_id + log.info("Creating image '%s'", name) + image = shade_client.create_image( + name, filename=filename, container=container, md5=md5, sha256=sha256, + disk_format=disk_format, container_format=container_format, + disable_vendor_agent=disable_vendor_agent, wait=wait, timeout=timeout, + allow_duplicates=allow_duplicates, meta=meta, volume=volume, **kwargs) + image_id = image["id"] return image_id - except Exception: # pylint: disable=broad-except - log.error( - "Error [create_glance_image(glance_client, '%s', '%s', '%s')]", - image_name, file_path, public) - return None + except exc.OpenStackCloudException as op_exc: + log.error("Failed to create_image(shade_client). " + "Exception message: %s", op_exc.orig_message) -def delete_image(glance_client, image_id): # pragma: no cover +def delete_image(shade_client, name_or_id, wait=False, timeout=3600, + delete_objects=True): try: - glance_client.images.delete(image_id) + return shade_client.delete_image(name_or_id, wait=wait, + timeout=timeout, + delete_objects=delete_objects) - except Exception: # pylint: disable=broad-except - log.exception("Error [delete_flavor(glance_client, %s)]", image_id) + except exc.OpenStackCloudException as op_exc: + log.error("Failed to delete_image(shade_client). " + "Exception message: %s", op_exc.orig_message) return False - else: - return True def list_images(shade_client=None): diff --git a/yardstick/common/utils.py b/yardstick/common/utils.py index 108ee17bc..c019cd264 100644 --- a/yardstick/common/utils.py +++ b/yardstick/common/utils.py @@ -28,6 +28,7 @@ import socket import subprocess import sys import time +import threading import six from flask import jsonify @@ -193,20 +194,16 @@ def parse_ini_file(path): def get_port_mac(sshclient, port): cmd = "ifconfig |grep HWaddr |grep %s |awk '{print $5}' " % port - status, stdout, stderr = sshclient.execute(cmd) + _, stdout, _ = sshclient.execute(cmd, raise_on_error=True) - if status: - raise RuntimeError(stderr) return stdout.rstrip() def get_port_ip(sshclient, port): cmd = "ifconfig %s |grep 'inet addr' |awk '{print $2}' " \ "|cut -d ':' -f2 " % port - status, stdout, stderr = sshclient.execute(cmd) + _, stdout, _ = sshclient.execute(cmd, raise_on_error=True) - if status: - raise RuntimeError(stderr) return stdout.rstrip() @@ -281,11 +278,19 @@ def get_free_port(ip): def mac_address_to_hex_list(mac): - octets = ["0x{:02x}".format(int(elem, 16)) for elem in mac.split(':')] - assert len(octets) == 6 and all(len(octet) == 4 for octet in octets) + try: + octets = ["0x{:02x}".format(int(elem, 16)) for elem in mac.split(':')] + except ValueError: + raise exceptions.InvalidMacAddress(mac_address=mac) + if len(octets) != 6 or all(len(octet) != 4 for octet in octets): + raise exceptions.InvalidMacAddress(mac_address=mac) return octets +def make_ipv4_address(ip_addr): + return ipaddress.IPv4Address(six.text_type(ip_addr)) + + def safe_ip_address(ip_addr): """ get ip address version v6 or v4 """ try: @@ -306,6 +311,19 @@ def get_ip_version(ip_addr): return address.version +def make_ip_addr(ip, mask): + """ + :param ip[str]: ip adddress + :param mask[str]: /24 prefix of 255.255.255.0 netmask + :return: IPv4Interface object + """ + try: + return ipaddress.ip_interface(six.text_type('/'.join([ip, mask]))) + except (TypeError, ValueError): + # None so we can skip later + return None + + def ip_to_hex(ip_addr, separator=''): try: address = ipaddress.ip_address(six.text_type(ip_addr)) @@ -322,6 +340,14 @@ def ip_to_hex(ip_addr, separator=''): return separator.join('{:02x}'.format(octet) for octet in address.packed) +def get_mask_from_ip_range(ip_low, ip_high): + _ip_low = ipaddress.ip_address(ip_low) + _ip_high = ipaddress.ip_address(ip_high) + _ip_low_int = int(_ip_low) + _ip_high_int = int(_ip_high) + return _ip_high.max_prefixlen - (_ip_high_int ^ _ip_low_int).bit_length() + + def try_int(s, *args): """Convert to integer if possible.""" try: @@ -409,13 +435,18 @@ class ErrorClass(object): class Timer(object): - def __init__(self, timeout=None): + def __init__(self, timeout=None, raise_exception=True): super(Timer, self).__init__() self.start = self.delta = None self._timeout = int(timeout) if timeout else None + self._timeout_flag = False + self._raise_exception = raise_exception def _timeout_handler(self, *args): - raise exceptions.TimerTimeout(timeout=self._timeout) + self._timeout_flag = True + if self._raise_exception: + raise exceptions.TimerTimeout(timeout=self._timeout) + self.__exit__() def __enter__(self): self.start = datetime.datetime.now() @@ -432,6 +463,26 @@ class Timer(object): def __getattr__(self, item): return getattr(self.delta, item) + def __iter__(self): + self._raise_exception = False + return self.__enter__() + + def next(self): # pragma: no cover + # NOTE(ralonsoh): Python 2 support. + if not self._timeout_flag: + return datetime.datetime.now() + raise StopIteration() + + def __next__(self): # pragma: no cover + # NOTE(ralonsoh): Python 3 support. + return self.next() + + def __del__(self): # pragma: no cover + signal.alarm(0) + + def delta_time_sec(self): + return (datetime.datetime.now() - self.start).total_seconds() + def read_meminfo(ssh_client): """Read "/proc/meminfo" file and parse all keys and values""" @@ -478,17 +529,52 @@ def open_relative_file(path, task_path): def wait_until_true(predicate, timeout=60, sleep=1, exception=None): """Wait until callable predicate is evaluated as True + When in a thread different from the main one, Timer(timeout) will fail + because signal is not handled. In this case + :param predicate: (func) callable deciding whether waiting should continue :param timeout: (int) timeout in seconds how long should function wait :param sleep: (int) polling interval for results in seconds :param exception: exception instance to raise on timeout. If None is passed (default) then WaitTimeout exception is raised. """ - try: - with Timer(timeout=timeout): - while not predicate(): + if isinstance(threading.current_thread(), threading._MainThread): + try: + with Timer(timeout=timeout): + while not predicate(): + time.sleep(sleep) + except exceptions.TimerTimeout: + if exception and issubclass(exception, Exception): + raise exception # pylint: disable=raising-bad-type + raise exceptions.WaitTimeout + else: + with Timer() as timer: + while timer.delta_time_sec() < timeout: + if predicate(): + return time.sleep(sleep) - except exceptions.TimerTimeout: if exception and issubclass(exception, Exception): raise exception # pylint: disable=raising-bad-type raise exceptions.WaitTimeout + + +def send_socket_command(host, port, command): + """Send a string command to a specific port in a host + + :param host: (str) ip or hostname of the host + :param port: (int) port number + :param command: (str) command to send + :return: 0 if success, error number if error + """ + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + ret = 0 + try: + err_number = sock.connect_ex((host, int(port))) + if err_number != 0: + return err_number + sock.sendall(six.b(command)) + except Exception: # pylint: disable=broad-except + ret = 1 + finally: + sock.close() + return ret diff --git a/yardstick/common/yaml_loader.py b/yardstick/common/yaml_loader.py index 0572bd582..18673be7c 100644 --- a/yardstick/common/yaml_loader.py +++ b/yardstick/common/yaml_loader.py @@ -10,10 +10,6 @@ # License for the specific language governing permissions and limitations # under the License. -# yardstick: this file is copied from python-heatclient and slightly modified - -from __future__ import absolute_import - import yaml @@ -23,6 +19,7 @@ if hasattr(yaml, 'CSafeLoader'): else: yaml_loader = type('CustomLoader', (yaml.SafeLoader,), {}) + if hasattr(yaml, 'CSafeDumper'): yaml_dumper = yaml.CSafeDumper else: @@ -31,3 +28,10 @@ else: def yaml_load(tmpl_str): return yaml.load(tmpl_str, Loader=yaml_loader) + + +def read_yaml_file(path): + """Read yaml file""" + with open(path) as stream: + data = yaml_load(stream) + return data diff --git a/yardstick/dispatcher/__init__.py b/yardstick/dispatcher/__init__.py index dfb130760..837a4397c 100644 --- a/yardstick/dispatcher/__init__.py +++ b/yardstick/dispatcher/__init__.py @@ -7,12 +7,12 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -from __future__ import absolute_import from oslo_config import cfg import yardstick.common.utils as utils -utils.import_modules_from_package("yardstick.dispatcher") +utils.import_modules_from_package('yardstick.dispatcher') + CONF = cfg.CONF OPTS = [ @@ -21,3 +21,8 @@ OPTS = [ help='Dispatcher to store data.'), ] CONF.register_opts(OPTS) + +# Dispatchers +FILE = 'file' +HTTP = 'http' +INFLUXDB = 'influxdb' diff --git a/yardstick/error.py b/yardstick/error.py deleted file mode 100644 index 9b84de1af..000000000 --- a/yardstick/error.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright (c) 2016-2017 Intel Corporation -# -# 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. - - -class SSHError(Exception): - """Class handles ssh connection error exception""" - pass - - -class SSHTimeout(SSHError): - """Class handles ssh connection timeout exception""" - pass - - -class IncorrectConfig(Exception): - """Class handles incorrect configuration during setup""" - pass - - -class IncorrectSetup(Exception): - """Class handles incorrect setup during setup""" - pass - - -class IncorrectNodeSetup(IncorrectSetup): - """Class handles incorrect setup during setup""" - pass - - -class ErrorClass(object): - - def __init__(self, *args, **kwargs): - if 'test' not in kwargs: - raise RuntimeError - - def __getattr__(self, item): - raise AttributeError diff --git a/yardstick/network_services/collector/subscriber.py b/yardstick/network_services/collector/subscriber.py index 322b3f5a2..0c6d97771 100644 --- a/yardstick/network_services/collector/subscriber.py +++ b/yardstick/network_services/collector/subscriber.py @@ -11,20 +11,40 @@ # 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. -"""This module implements stub for publishing results in yardstick format.""" + import logging +from yardstick.network_services.nfvi.resource import ResourceProfile +from yardstick.network_services.utils import get_nsb_option + + LOG = logging.getLogger(__name__) class Collector(object): """Class that handles dictionary of results in yardstick-plot format.""" - def __init__(self, vnfs): + def __init__(self, vnfs, contexts_nodes, timeout=3600): super(Collector, self).__init__() self.vnfs = vnfs + self.nodes = contexts_nodes + self.bin_path = get_nsb_option('bin_path', '') + self.resource_profiles = {} + + for ctx_name, nodes in ((ctx_name, nodes) for (ctx_name, nodes) + in contexts_nodes.items() if nodes): + for node in (node for node in nodes + if node and node.get('collectd')): + name = ".".join([node['name'], ctx_name]) + self.resource_profiles.update( + {name: ResourceProfile.make_from_node(node, timeout)}) def start(self): + for resource in self.resource_profiles.values(): + resource.initiate_systemagent(self.bin_path) + resource.start() + resource.amqp_process_for_nfvi_kpi() + for vnf in self.vnfs: vnf.start_collect() @@ -32,6 +52,9 @@ class Collector(object): for vnf in self.vnfs: vnf.stop_collect() + for resource in self.resource_profiles.values(): + resource.stop() + def get_kpi(self): """Returns dictionary of results in yardstick-plot format @@ -42,7 +65,12 @@ class Collector(object): for vnf in self.vnfs: # Result example: # {"VNF1: { "tput" : [1000, 999] }, "VNF2": { "latency": 100 }} - LOG.debug("collect KPI for %s", vnf.name) + LOG.debug("collect KPI for vnf %s", vnf.name) results[vnf.name] = vnf.collect_kpi() + for node_name, resource in self.resource_profiles.items(): + LOG.debug("collect KPI for nfvi_node %s", node_name) + results[node_name] = {"core": resource.amqp_collect_nfvi_kpi()} + LOG.debug("%s collect KPIs %s", node_name, results[node_name]['core']) + return results diff --git a/yardstick/network_services/helpers/dpdkbindnic_helper.py b/yardstick/network_services/helpers/dpdkbindnic_helper.py index 05b822c2e..1c74355ef 100644 --- a/yardstick/network_services/helpers/dpdkbindnic_helper.py +++ b/yardstick/network_services/helpers/dpdkbindnic_helper.py @@ -18,12 +18,9 @@ import re from collections import defaultdict from itertools import chain +from yardstick.common import exceptions from yardstick.common.utils import validate_non_string_sequence -from yardstick.error import IncorrectConfig -from yardstick.error import IncorrectSetup -from yardstick.error import IncorrectNodeSetup -from yardstick.error import SSHTimeout -from yardstick.error import SSHError + NETWORK_KERNEL = 'network_kernel' NETWORK_DPDK = 'network_dpdk' @@ -51,7 +48,7 @@ class DpdkInterface(object): try: assert self.local_mac except (AssertionError, KeyError): - raise IncorrectConfig + raise exceptions.IncorrectConfig(error_msg='') @property def local_mac(self): @@ -98,10 +95,12 @@ class DpdkInterface(object): # if we don't find all the keys then don't update pass - except (IncorrectNodeSetup, SSHError, SSHTimeout): - raise IncorrectConfig( - "Unable to probe missing interface fields '%s', on node %s " - "SSH Error" % (', '.join(self.missing_fields), self.dpdk_node.node_key)) + except (exceptions.IncorrectNodeSetup, exceptions.SSHError, + exceptions.SSHTimeout): + message = ('Unable to probe missing interface fields "%s", on ' + 'node %s SSH Error' % (', '.join(self.missing_fields), + self.dpdk_node.node_key)) + raise exceptions.IncorrectConfig(error_msg=message) class DpdkNode(object): @@ -118,11 +117,12 @@ class DpdkNode(object): try: self.dpdk_interfaces = {intf['name']: DpdkInterface(self, intf['virtual-interface']) for intf in self.interfaces} - except IncorrectConfig: + except exceptions.IncorrectConfig: template = "MAC address is required for all interfaces, missing on: {}" errors = (intf['name'] for intf in self.interfaces if 'local_mac' not in intf['virtual-interface']) - raise IncorrectSetup(template.format(", ".join(errors))) + raise exceptions.IncorrectSetup( + error_msg=template.format(", ".join(errors))) @property def dpdk_helper(self): @@ -176,7 +176,7 @@ class DpdkNode(object): self._probe_netdevs() try: self._probe_missing_values() - except IncorrectConfig: + except exceptions.IncorrectConfig: # ignore for now pass @@ -193,7 +193,7 @@ class DpdkNode(object): missing_fields) errors = "\n".join(errors) if errors: - raise IncorrectSetup(errors) + raise exceptions.IncorrectSetup(error_msg=errors) finally: self._dpdk_helper = None diff --git a/yardstick/network_services/helpers/samplevnf_helper.py b/yardstick/network_services/helpers/samplevnf_helper.py index 0ab10d7b7..8e6a3a3ea 100644 --- a/yardstick/network_services/helpers/samplevnf_helper.py +++ b/yardstick/network_services/helpers/samplevnf_helper.py @@ -23,8 +23,7 @@ from itertools import chain, repeat import six from six.moves.configparser import ConfigParser - -from yardstick.common.utils import ip_to_hex +from yardstick.common import utils LOG = logging.getLogger(__name__) @@ -34,19 +33,6 @@ link {0} config {1} {2} link {0} up """ -ACTION_TEMPLATE = """\ -p action add {0} accept -p action add {0} fwd {0} -p action add {0} count -""" - -FW_ACTION_TEMPLATE = """\ -p action add {0} accept -p action add {0} fwd {0} -p action add {0} count -p action add {0} conntrack -""" - # This sets up a basic passthrough with no rules SCRIPT_TPL = """ {link_config} @@ -59,9 +45,7 @@ SCRIPT_TPL = """ {arp_route_tbl6} -{actions} - -{rules} +{flows} """ @@ -182,26 +166,9 @@ class MultiPortConfig(object): return parser.get(section, key) return default - @staticmethod - def make_ip_addr(ip, mask): - """ - :param ip: ip adddress - :type ip: str - :param mask: /24 prefix of 255.255.255.0 netmask - :type mask: str - :return: interface - :rtype: IPv4Interface - """ - - try: - return ipaddress.ip_interface(six.text_type('/'.join([ip, mask]))) - except (TypeError, ValueError): - # None so we can skip later - return None - @classmethod def validate_ip_and_prefixlen(cls, ip_addr, prefixlen): - ip_addr = cls.make_ip_addr(ip_addr, prefixlen) + ip_addr = utils.make_ip_addr(ip_addr, prefixlen) return ip_addr.ip.exploded, ip_addr.network.prefixlen def __init__(self, topology_file, config_tpl, tmp_file, vnfd_helper, @@ -245,7 +212,7 @@ class MultiPortConfig(object): self.ports_len = 0 self.prv_que_handler = None self.vnfd = None - self.rules = None + self.flows = None self.pktq_out = [] @staticmethod @@ -360,7 +327,7 @@ class MultiPortConfig(object): "%s/%s" % (interface["dst_ip"], interface["netmask"]))) arp_vars = { - "port_netmask_hex": ip_to_hex(dst_port_ip.network.netmask.exploded), + "port_netmask_hex": utils.ip_to_hex(dst_port_ip.network.netmask.exploded), # this is the port num that contains port0 subnet and next_hop_ip_hex # this is LINKID which should be based on DPDK port number "port_num": dpdk_port_num, @@ -542,7 +509,7 @@ class MultiPortConfig(object): self.update_write_parser(self.loadb_tpl) self.start_core += 1 - for i in range(self.worker_threads): + for _ in range(self.worker_threads): vnf_data = self.generate_vnf_data() if not self.vnf_tpl: self.vnf_tpl = {} @@ -637,65 +604,8 @@ class MultiPortConfig(object): return '\n'.join(('p {3} arpadd {0} {1} {2}'.format(*values) for values in arp_config6)) - def generate_action_config(self): - port_list = (self.vnfd_helper.port_num(p) for p in self.all_ports) - if self.vnf_type == "VFW": - template = FW_ACTION_TEMPLATE - else: - template = ACTION_TEMPLATE - - return ''.join((template.format(port) for port in port_list)) - - def get_ip_from_port(self, port): - # we can't use gateway because in OpenStack gateways interfer with floating ip routing - # return self.make_ip_addr(self.get_ports_gateway(port), self.get_netmask_gateway(port)) - vintf = self.vnfd_helper.find_interface(name=port)["virtual-interface"] - ip = vintf["local_ip"] - netmask = vintf["netmask"] - return self.make_ip_addr(ip, netmask) - - def get_network_and_prefixlen_from_ip_of_port(self, port): - ip_addr = self.get_ip_from_port(port) - # handle cases with no gateway - if ip_addr: - return ip_addr.network.network_address.exploded, ip_addr.network.prefixlen - else: - return None, None - - def generate_rule_config(self): - cmd = 'acl' if self.vnf_type == "ACL" else "vfw" - rules_config = self.rules if self.rules else '' - new_rules = [] - new_ipv6_rules = [] - pattern = 'p {0} add {1} {2} {3} {4} {5} 0 65535 0 65535 0 0 {6}' - for src_intf, dst_intf in self.port_pair_list: - src_port = self.vnfd_helper.port_num(src_intf) - dst_port = self.vnfd_helper.port_num(dst_intf) - - src_net, src_prefix_len = self.get_network_and_prefixlen_from_ip_of_port(src_intf) - dst_net, dst_prefix_len = self.get_network_and_prefixlen_from_ip_of_port(dst_intf) - # ignore entires with empty values - if all((src_net, src_prefix_len, dst_net, dst_prefix_len)): - new_rules.append((cmd, self.txrx_pipeline, src_net, src_prefix_len, - dst_net, dst_prefix_len, dst_port)) - new_rules.append((cmd, self.txrx_pipeline, dst_net, dst_prefix_len, - src_net, src_prefix_len, src_port)) - - # src_net = self.get_ports_gateway6(port_pair[0]) - # src_prefix_len = self.get_netmask_gateway6(port_pair[0]) - # dst_net = self.get_ports_gateway6(port_pair[1]) - # dst_prefix_len = self.get_netmask_gateway6(port_pair[0]) - # # ignore entires with empty values - # if all((src_net, src_prefix_len, dst_net, dst_prefix_len)): - # new_ipv6_rules.append((cmd, self.txrx_pipeline, src_net, src_prefix_len, - # dst_net, dst_prefix_len, dst_port)) - # new_ipv6_rules.append((cmd, self.txrx_pipeline, dst_net, dst_prefix_len, - # src_net, src_prefix_len, src_port)) - - acl_apply = "\np %s applyruleset" % cmd - new_rules_config = '\n'.join(pattern.format(*values) for values - in chain(new_rules, new_ipv6_rules)) - return ''.join([rules_config, new_rules_config, acl_apply]) + def get_flows_config(self): + return self.flows if self.flows else '' def generate_script_data(self): self._port_pairs = PortPairs(self.vnfd_helper.interfaces) @@ -707,24 +617,15 @@ class MultiPortConfig(object): # disable IPv6 for now # 'arp_config6': self.generate_arp_config6(), 'arp_config6': "", - 'arp_config': self.generate_arp_config(), 'arp_route_tbl': self.generate_arp_route_tbl(), 'arp_route_tbl6': "", - 'actions': '', - 'rules': '', + 'flows': self.get_flows_config() } - - if self.vnf_type in ('ACL', 'VFW'): - script_data.update({ - 'actions': self.generate_action_config(), - 'rules': self.generate_rule_config(), - }) - return script_data - def generate_script(self, vnfd, rules=None): + def generate_script(self, vnfd, flows=None): self.vnfd = vnfd - self.rules = rules + self.flows = flows script_data = self.generate_script_data() script = SCRIPT_TPL.format(**script_data) if self.lb_config == self.HW_LB: diff --git a/yardstick/network_services/libs/ixia_libs/IxNet/IxNet.py b/yardstick/network_services/libs/ixia_libs/IxNet/IxNet.py deleted file mode 100644 index c538ceeba..000000000 --- a/yardstick/network_services/libs/ixia_libs/IxNet/IxNet.py +++ /dev/null @@ -1,334 +0,0 @@ -# Copyright (c) 2016-2017 Intel Corporation -# -# 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. - -import logging - -import re -from itertools import product -import IxNetwork - - -log = logging.getLogger(__name__) - -IP_VERSION_4 = 4 -IP_VERSION_6 = 6 - - -class TrafficStreamHelper(object): - - TEMPLATE = '{0.traffic_item}/{0.stream}:{0.param_id}/{1}' - - def __init__(self, traffic_item, stream, param_id): - super(TrafficStreamHelper, self).__init__() - self.traffic_item = traffic_item - self.stream = stream - self.param_id = param_id - - def __getattr__(self, item): - return self.TEMPLATE.format(self, item) - - -class FramesizeHelper(object): - - def __init__(self): - super(FramesizeHelper, self).__init__() - self.weighted_pairs = [] - self.weighted_range_pairs = [] - - @property - def weighted_pairs_arg(self): - return '-weightedPairs', self.weighted_pairs - - @property - def weighted_range_pairs_arg(self): - return '-weightedRangePairs', self.weighted_range_pairs - - def make_args(self, *args): - return self.weighted_pairs_arg + self.weighted_range_pairs_arg + args - - def populate_data(self, framesize_data): - for key, value in framesize_data.items(): - if value == '0': - continue - - replaced = re.sub('[Bb]', '', key) - self.weighted_pairs.extend([ - replaced, - value, - ]) - pairs = [ - replaced, - replaced, - value, - ] - self.weighted_range_pairs.append(pairs) - - -class IxNextgen(object): - - STATS_NAME_MAP = { - "traffic_item": 'Traffic Item', - "Tx_Frames": 'Tx Frames', - "Rx_Frames": 'Rx Frames', - "Tx_Frame_Rate": 'Tx Frame Rate', - "Rx_Frame_Rate": 'Tx Frame Rate', - "Store-Forward_Avg_latency_ns": 'Store-Forward Avg Latency (ns)', - "Store-Forward_Min_latency_ns": 'Store-Forward Min Latency (ns)', - "Store-Forward_Max_latency_ns": 'Store-Forward Max Latency (ns)', - } - - PORT_STATS_NAME_MAP = { - "stat_name": 'Stat Name', - "Frames_Tx": 'Frames Tx.', - "Valid_Frames_Rx": 'Valid Frames Rx.', - "Frames_Tx_Rate": 'Frames Tx. Rate', - "Valid_Frames_Rx_Rate": 'Valid Frames Rx. Rate', - "Tx_Rate_Kbps": 'Tx. Rate (Kbps)', - "Rx_Rate_Kbps": 'Rx. Rate (Kbps)', - "Tx_Rate_Mbps": 'Tx. Rate (Mbps)', - "Rx_Rate_Mbps": 'Rx. Rate (Mbps)', - } - - LATENCY_NAME_MAP = { - "Store-Forward_Avg_latency_ns": 'Store-Forward Avg Latency (ns)', - "Store-Forward_Min_latency_ns": 'Store-Forward Min Latency (ns)', - "Store-Forward_Max_latency_ns": 'Store-Forward Max Latency (ns)', - } - - RANDOM_MASK_MAP = { - IP_VERSION_4: '0.0.0.255', - IP_VERSION_6: '0:0:0:0:0:0:0:ff', - } - - MODE_SEEDS_MAP = { - 0: ('uplink', ['256', '2048']), - } - - MODE_SEEDS_DEFAULT = 'downlink', ['2048', '256'] - - @staticmethod - def find_view_obj(view_name, views): - edited_view_name = '::ixNet::OBJ-/statistics/view:"{}"'.format(view_name) - return next((view for view in views if edited_view_name == view), '') - - @staticmethod - def get_config(tg_cfg): - card = [] - port = [] - external_interface = tg_cfg["vdu"][0]["external-interface"] - for intf in external_interface: - card_port0 = intf["virtual-interface"]["vpci"] - card0, port0 = card_port0.split(':')[:2] - card.append(card0) - port.append(port0) - - cfg = { - 'machine': tg_cfg["mgmt-interface"]["ip"], - 'port': tg_cfg["mgmt-interface"]["tg-config"]["tcl_port"], - 'chassis': tg_cfg["mgmt-interface"]["tg-config"]["ixchassis"], - 'cards': card, - 'ports': port, - 'output_dir': tg_cfg["mgmt-interface"]["tg-config"]["dut_result_dir"], - 'version': tg_cfg["mgmt-interface"]["tg-config"]["version"], - 'bidir': True, - } - - return cfg - - def __init__(self, ixnet=None): - self.ixnet = ixnet - self._objRefs = dict() - self._cfg = None - self._logger = logging.getLogger(__name__) - self._params = None - self._bidir = None - - def iter_over_get_lists(self, x1, x2, y2, offset=0): - for x in self.ixnet.getList(x1, x2): - y_list = self.ixnet.getList(x, y2) - for i, y in enumerate(y_list, offset): - yield x, y, i - - def set_random_ip_multi_attribute(self, ipv4, seed, fixed_bits, random_mask, l3_count): - self.ixnet.setMultiAttribute( - ipv4, - '-seed', str(seed), - '-fixedBits', str(fixed_bits), - '-randomMask', str(random_mask), - '-valueType', 'random', - '-countValue', str(l3_count)) - - def set_random_ip_multi_attributes(self, ip, version, seeds, l3): - try: - random_mask = self.RANDOM_MASK_MAP[version] - except KeyError: - raise ValueError('Unknown version %s' % version) - - l3_count = l3['count'] - if "srcIp" in ip: - fixed_bits = l3['srcip4'] - self.set_random_ip_multi_attribute(ip, seeds[0], fixed_bits, random_mask, l3_count) - if "dstIp" in ip: - fixed_bits = l3['dstip4'] - self.set_random_ip_multi_attribute(ip, seeds[1], fixed_bits, random_mask, l3_count) - - def add_ip_header(self, params, version): - for _, ep, i in self.iter_over_get_lists('/traffic', 'trafficItem', "configElement", 1): - iter1 = (v['outer_l3'] for v in params.values() if str(v['id']) == str(i)) - try: - l3 = next(iter1, {}) - seeds = self.MODE_SEEDS_MAP.get(i, self.MODE_SEEDS_DEFAULT)[1] - except (KeyError, IndexError): - continue - - for _, ip_bits, _ in self.iter_over_get_lists(ep, 'stack', 'field'): - self.set_random_ip_multi_attributes(ip_bits, version, seeds, l3) - - self.ixnet.commit() - - def _connect(self, tg_cfg): - self._cfg = self.get_config(tg_cfg) - self.ixnet = IxNetwork.IxNet() - - machine = self._cfg['machine'] - port = str(self._cfg['port']) - version = str(self._cfg['version']) - result = self.ixnet.connect(machine, '-port', port, '-version', version) - return result - - def clear_ixia_config(self): - self.ixnet.execute('newConfig') - - def load_ixia_profile(self, profile): - self.ixnet.execute('loadConfig', self.ixnet.readFrom(profile)) - - def ix_load_config(self, profile): - self.clear_ixia_config() - self.load_ixia_profile(profile) - - def ix_assign_ports(self): - vports = self.ixnet.getList(self.ixnet.getRoot(), 'vport') - ports = [] - - chassis = self._cfg['chassis'] - ports = [(chassis, card, port) for card, port in - zip(self._cfg['cards'], self._cfg['ports'])] - - vport_list = self.ixnet.getList("/", "vport") - self.ixnet.execute('assignPorts', ports, [], vport_list, True) - self.ixnet.commit() - - for vport in vports: - if self.ixnet.getAttribute(vport, '-state') != 'up': - log.error("Both thr ports are down...") - - def ix_update_frame(self, params): - streams = ["configElement"] - - for param in params.values(): - framesize_data = FramesizeHelper() - traffic_items = self.ixnet.getList('/traffic', 'trafficItem') - param_id = param['id'] - for traffic_item, stream in product(traffic_items, streams): - helper = TrafficStreamHelper(traffic_item, stream, param_id) - - self.ixnet.setMultiAttribute(helper.transmissionControl, - '-type', '{0}'.format(param.get('traffic_type', - 'continuous')), - '-duration', '{0}'.format(param.get('duration', - "30"))) - - stream_frame_rate_path = helper.frameRate - self.ixnet.setMultiAttribute(stream_frame_rate_path, '-rate', param['iload']) - if param['outer_l2']['framesPerSecond']: - self.ixnet.setMultiAttribute(stream_frame_rate_path, - '-type', 'framesPerSecond') - - framesize_data.populate_data(param['outer_l2']['framesize']) - - make_attr_args = framesize_data.make_args('-incrementFrom', '66', - '-randomMin', '66', - '-quadGaussian', [], - '-type', 'weightedPairs', - '-presetDistribution', 'cisco', - '-incrementTo', '1518') - - self.ixnet.setMultiAttribute(helper.frameSize, *make_attr_args) - - self.ixnet.commit() - - def update_ether_multi_attribute(self, ether, mac_addr): - self.ixnet.setMultiAttribute(ether, - '-singleValue', mac_addr, - '-fieldValue', mac_addr, - '-valueType', 'singleValue') - - def update_ether_multi_attributes(self, ether, l2): - if "ethernet.header.destinationAddress" in ether: - self.update_ether_multi_attribute(ether, str(l2.get('dstmac', "00:00:00:00:00:02"))) - - if "ethernet.header.sourceAddress" in ether: - self.update_ether_multi_attribute(ether, str(l2.get('srcmac', "00:00:00:00:00:01"))) - - def ix_update_ether(self, params): - for _, ep, index in self.iter_over_get_lists('/traffic', 'trafficItem', - "configElement", 1): - iter1 = (v['outer_l2'] for v in params.values() if str(v['id']) == str(index)) - try: - l2 = next(iter1, {}) - except KeyError: - continue - - for _, ether, _ in self.iter_over_get_lists(ep, 'stack', 'field'): - self.update_ether_multi_attributes(ether, l2) - - self.ixnet.commit() - - def ix_update_udp(self, params): - pass - - def ix_update_tcp(self, params): - pass - - def ix_start_traffic(self): - tis = self.ixnet.getList('/traffic', 'trafficItem') - for ti in tis: - self.ixnet.execute('generate', [ti]) - self.ixnet.execute('apply', '/traffic') - self.ixnet.execute('start', '/traffic') - - def ix_stop_traffic(self): - tis = self.ixnet.getList('/traffic', 'trafficItem') - for _ in tis: - self.ixnet.execute('stop', '/traffic') - - def build_stats_map(self, view_obj, name_map): - return {kl: self.execute_get_column_values(view_obj, kr) for kl, kr in name_map.items()} - - def execute_get_column_values(self, view_obj, name): - return self.ixnet.execute('getColumnValues', view_obj, name) - - def ix_get_statistics(self): - views = self.ixnet.getList('/statistics', 'view') - stats = {} - view_obj = self.find_view_obj("Traffic Item Statistics", views) - stats = self.build_stats_map(view_obj, self.STATS_NAME_MAP) - - view_obj = self.find_view_obj("Port Statistics", views) - ports_stats = self.build_stats_map(view_obj, self.PORT_STATS_NAME_MAP) - - view_obj = self.find_view_obj("Flow Statistics", views) - stats["latency"] = self.build_stats_map(view_obj, self.LATENCY_NAME_MAP) - - return stats, ports_stats diff --git a/tests/unit/network_services/__init__.py b/yardstick/network_services/libs/ixia_libs/ixnet/__init__.py index e69de29bb..e69de29bb 100644 --- a/tests/unit/network_services/__init__.py +++ b/yardstick/network_services/libs/ixia_libs/ixnet/__init__.py diff --git a/yardstick/network_services/libs/ixia_libs/ixnet/ixnet_api.py b/yardstick/network_services/libs/ixia_libs/ixnet/ixnet_api.py new file mode 100644 index 000000000..82f406d08 --- /dev/null +++ b/yardstick/network_services/libs/ixia_libs/ixnet/ixnet_api.py @@ -0,0 +1,543 @@ +# Copyright (c) 2016-2017 Intel Corporation +# +# 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. + +import ipaddress +import logging + +import IxNetwork + +from yardstick.common import exceptions +from yardstick.common import utils +from yardstick.network_services.traffic_profile import base as tp_base + + +log = logging.getLogger(__name__) + +IP_VERSION_4 = 4 +IP_VERSION_6 = 6 + +PROTO_ETHERNET = 'ethernet' +PROTO_IPV4 = 'ipv4' +PROTO_IPV6 = 'ipv6' +PROTO_UDP = 'udp' +PROTO_TCP = 'tcp' +PROTO_VLAN = 'vlan' + +IP_VERSION_4_MASK = 24 +IP_VERSION_6_MASK = 64 + +TRAFFIC_STATUS_STARTED = 'started' +TRAFFIC_STATUS_STOPPED = 'stopped' + +SUPPORTED_PROTO = [PROTO_UDP] + + +# NOTE(ralonsoh): this pragma will be removed in the last patch of this series +class IxNextgen(object): # pragma: no cover + + PORT_STATS_NAME_MAP = { + "stat_name": 'Stat Name', + "Frames_Tx": 'Frames Tx.', + "Valid_Frames_Rx": 'Valid Frames Rx.', + "Frames_Tx_Rate": 'Frames Tx. Rate', + "Valid_Frames_Rx_Rate": 'Valid Frames Rx. Rate', + "Tx_Rate_Kbps": 'Tx. Rate (Kbps)', + "Rx_Rate_Kbps": 'Rx. Rate (Kbps)', + "Tx_Rate_Mbps": 'Tx. Rate (Mbps)', + "Rx_Rate_Mbps": 'Rx. Rate (Mbps)', + } + + LATENCY_NAME_MAP = { + "Store-Forward_Avg_latency_ns": 'Store-Forward Avg Latency (ns)', + "Store-Forward_Min_latency_ns": 'Store-Forward Min Latency (ns)', + "Store-Forward_Max_latency_ns": 'Store-Forward Max Latency (ns)', + } + + @staticmethod + def get_config(tg_cfg): + card = [] + port = [] + external_interface = tg_cfg["vdu"][0]["external-interface"] + for intf in external_interface: + card_port0 = intf["virtual-interface"]["vpci"] + card0, port0 = card_port0.split(':')[:2] + card.append(card0) + port.append(port0) + + cfg = { + 'machine': tg_cfg["mgmt-interface"]["ip"], + 'port': tg_cfg["mgmt-interface"]["tg-config"]["tcl_port"], + 'chassis': tg_cfg["mgmt-interface"]["tg-config"]["ixchassis"], + 'cards': card, + 'ports': port, + 'output_dir': tg_cfg["mgmt-interface"]["tg-config"]["dut_result_dir"], + 'version': tg_cfg["mgmt-interface"]["tg-config"]["version"], + 'bidir': True, + } + + return cfg + + def __init__(self): # pragma: no cover + self._ixnet = None + self._cfg = None + self._params = None + self._bidir = None + + @property + def ixnet(self): # pragma: no cover + if self._ixnet: + return self._ixnet + raise exceptions.IxNetworkClientNotConnected() + + def _get_config_element_by_flow_group_name(self, flow_group_name): + """Get a config element using the flow group name + + Each named flow group contains one config element (by configuration). + According to the documentation, "configElements" is a list and "each + item in this list is aligned to the sequential order of your endpoint + list". + + :param flow_group_name: (str) flow group name; this parameter is + always a number (converted to string) starting + from "1". + :return: (str) config element reference ID or None. + """ + traffic_item = self.ixnet.getList(self.ixnet.getRoot() + '/traffic', + 'trafficItem')[0] + flow_groups = self.ixnet.getList(traffic_item, 'endpointSet') + for flow_group in flow_groups: + if (str(self.ixnet.getAttribute(flow_group, '-name')) == + flow_group_name): + return traffic_item + '/configElement:' + flow_group_name + + def _get_stack_item(self, flow_group_name, protocol_name): + """Return the stack item given the flow group name and the proto name + + :param flow_group_name: (str) flow group name + :param protocol_name: (str) protocol name, referred to PROTO_* + constants + :return: list of stack item descriptors + """ + celement = self._get_config_element_by_flow_group_name(flow_group_name) + if not celement: + raise exceptions.IxNetworkFlowNotPresent( + flow_group=flow_group_name) + stack_items = self.ixnet.getList(celement, 'stack') + return [s_i for s_i in stack_items if protocol_name in s_i] + + def _get_field_in_stack_item(self, stack_item, field_name): + """Return the field in a stack item given the name + + :param stack_item: (str) stack item descriptor + :param field_name: (str) field name + :return: (str) field descriptor + """ + fields = self.ixnet.getList(stack_item, 'field') + for field in (field for field in fields if field_name in field): + return field + raise exceptions.IxNetworkFieldNotPresentInStackItem( + field_name=field_name, stack_item=stack_item) + + def _get_traffic_state(self): + """Get traffic state""" + return self.ixnet.getAttribute(self.ixnet.getRoot() + 'traffic', + '-state') + + def is_traffic_running(self): + """Returns true if traffic state == TRAFFIC_STATUS_STARTED""" + return self._get_traffic_state() == TRAFFIC_STATUS_STARTED + + def is_traffic_stopped(self): + """Returns true if traffic state == TRAFFIC_STATUS_STOPPED""" + return self._get_traffic_state() == TRAFFIC_STATUS_STOPPED + + @staticmethod + def _parse_framesize(framesize): + """Parse "framesize" config param. to return a list of weighted pairs + + :param framesize: dictionary of frame sizes and weights + :return: list of paired frame sizes and weights + """ + weighted_range_pairs = [] + for size, weight in ((s, w) for (s, w) in framesize.items() + if int(w) != 0): + size = int(size.upper().replace('B', '')) + weighted_range_pairs.append([size, size, int(weight)]) + return weighted_range_pairs + + def iter_over_get_lists(self, x1, x2, y2, offset=0): + for x in self.ixnet.getList(x1, x2): + y_list = self.ixnet.getList(x, y2) + for i, y in enumerate(y_list, offset): + yield x, y, i + + def connect(self, tg_cfg): + self._cfg = self.get_config(tg_cfg) + self._ixnet = IxNetwork.IxNet() + + machine = self._cfg['machine'] + port = str(self._cfg['port']) + version = str(self._cfg['version']) + return self.ixnet.connect(machine, '-port', port, + '-version', version) + + def clear_config(self): + """Wipe out any possible configuration present in the client""" + self.ixnet.execute('newConfig') + + def assign_ports(self): + """Create and assign vports for each physical port defined in config + + This configuration is present in the IXIA profile file. E.g.: + name: trafficgen_1 + role: IxNet + interfaces: + xe0: + vpci: "2:15" # Card:port + driver: "none" + dpdk_port_num: 0 + local_ip: "152.16.100.20" + netmask: "255.255.0.0" + local_mac: "00:98:10:64:14:00" + xe1: + ... + """ + chassis_ip = self._cfg['chassis'] + ports = [(chassis_ip, card, port) for card, port in + zip(self._cfg['cards'], self._cfg['ports'])] + + log.info('Create and assign vports: %s', ports) + for port in ports: + vport = self.ixnet.add(self.ixnet.getRoot(), 'vport') + self.ixnet.commit() + self.ixnet.execute('assignPorts', [port], [], [vport], True) + self.ixnet.commit() + if self.ixnet.getAttribute(vport, '-state') != 'up': + log.warning('Port %s is down', vport) + + def _create_traffic_item(self): + """Create the traffic item to hold the flow groups + + The traffic item tracking by "Traffic Item" is enabled to retrieve the + latency statistics. + """ + log.info('Create the traffic item "RFC2544"') + traffic_item = self.ixnet.add(self.ixnet.getRoot() + '/traffic', + 'trafficItem') + self.ixnet.setMultiAttribute(traffic_item, '-name', 'RFC2544', + '-trafficType', 'raw') + self.ixnet.commit() + + traffic_item_id = self.ixnet.remapIds(traffic_item)[0] + self.ixnet.setAttribute(traffic_item_id + '/tracking', + '-trackBy', 'trafficGroupId0') + self.ixnet.commit() + + def _create_flow_groups(self): + """Create the flow groups between the assigned ports""" + traffic_item_id = self.ixnet.getList(self.ixnet.getRoot() + 'traffic', + 'trafficItem')[0] + log.info('Create the flow groups') + vports = self.ixnet.getList(self.ixnet.getRoot(), 'vport') + uplink_ports = vports[::2] + downlink_ports = vports[1::2] + index = 0 + for up, down in zip(uplink_ports, downlink_ports): + log.info('FGs: %s <--> %s', up, down) + endpoint_set_1 = self.ixnet.add(traffic_item_id, 'endpointSet') + endpoint_set_2 = self.ixnet.add(traffic_item_id, 'endpointSet') + self.ixnet.setMultiAttribute( + endpoint_set_1, '-name', str(index + 1), + '-sources', [up + '/protocols'], + '-destinations', [down + '/protocols']) + self.ixnet.setMultiAttribute( + endpoint_set_2, '-name', str(index + 2), + '-sources', [down + '/protocols'], + '-destinations', [up + '/protocols']) + self.ixnet.commit() + index += 2 + + def _append_procotol_to_stack(self, protocol_name, previous_element): + """Append a new element in the packet definition stack""" + protocol = (self.ixnet.getRoot() + + '/traffic/protocolTemplate:"{}"'.format(protocol_name)) + self.ixnet.execute('append', previous_element, protocol) + + def _setup_config_elements(self): + """Setup the config elements + + The traffic item is configured to allow individual configurations per + config element. The default frame configuration is applied: + Ethernet II: added by default + IPv4: element to add + UDP: element to add + Payload: added by default + Ethernet II (Trailer): added by default + :return: + """ + traffic_item_id = self.ixnet.getList(self.ixnet.getRoot() + 'traffic', + 'trafficItem')[0] + log.info('Split the frame rate distribution per config element') + config_elements = self.ixnet.getList(traffic_item_id, 'configElement') + for config_element in config_elements: + self.ixnet.setAttribute(config_element + '/frameRateDistribution', + '-portDistribution', 'splitRateEvenly') + self.ixnet.setAttribute(config_element + '/frameRateDistribution', + '-streamDistribution', 'splitRateEvenly') + self.ixnet.commit() + self._append_procotol_to_stack( + PROTO_UDP, config_element + '/stack:"ethernet-1"') + self._append_procotol_to_stack( + PROTO_IPV4, config_element + '/stack:"ethernet-1"') + + def create_traffic_model(self): + """Create a traffic item and the needed flow groups + + Each flow group inside the traffic item (only one is present) + represents the traffic between two ports: + (uplink) (downlink) + FlowGroup1: port1 -> port2 + FlowGroup2: port1 <- port2 + FlowGroup3: port3 -> port4 + FlowGroup4: port3 <- port4 + """ + self._create_traffic_item() + self._create_flow_groups() + self._setup_config_elements() + + def _update_frame_mac(self, ethernet_descriptor, field, mac_address): + """Set the MAC address in a config element stack Ethernet field + + :param ethernet_descriptor: (str) ethernet descriptor, e.g.: + /traffic/trafficItem:1/configElement:1/stack:"ethernet-1" + :param field: (str) field name, e.g.: destinationAddress + :param mac_address: (str) MAC address + """ + field_descriptor = self._get_field_in_stack_item(ethernet_descriptor, + field) + self.ixnet.setMultiAttribute(field_descriptor, + '-singleValue', mac_address, + '-fieldValue', mac_address, + '-valueType', 'singleValue') + self.ixnet.commit() + + def update_frame(self, traffic, duration): + """Update the L2 frame + + This function updates the L2 frame options: + - Traffic type: "continuous", "fixedDuration". + - Duration: in case of traffic_type="fixedDuration", amount of seconds + to inject traffic. + - Rate: in frames per seconds or percentage. + - Type of rate: "framesPerSecond" or "percentLineRate" ("bitsPerSecond" + no used) + - Frame size: custom IMIX [1] definition; a list of packet size in + bytes and the weight. E.g.: + [[64, 64, 10], [128, 128, 15], [512, 512, 5]] + + [1] https://en.wikipedia.org/wiki/Internet_Mix + + :param traffic: list of traffic elements; each traffic element contains + the injection parameter for each flow group. + :param duration: (int) injection time in seconds. + """ + for traffic_param in traffic.values(): + fg_id = str(traffic_param['id']) + config_element = self._get_config_element_by_flow_group_name(fg_id) + if not config_element: + raise exceptions.IxNetworkFlowNotPresent(flow_group=fg_id) + + type = traffic_param.get('traffic_type', 'fixedDuration') + duration = traffic_param.get('duration', 30) + rate = traffic_param['rate'] + rate_unit = ( + 'framesPerSecond' if traffic_param['rate_unit'] == + tp_base.TrafficProfileConfig.RATE_FPS else 'percentLineRate') + weighted_range_pairs = self._parse_framesize( + traffic_param['outer_l2']['framesize']) + srcmac = str(traffic_param.get('srcmac', '00:00:00:00:00:01')) + dstmac = str(traffic_param.get('dstmac', '00:00:00:00:00:02')) + # NOTE(ralonsoh): add QinQ tagging when + # traffic_param['outer_l2']['QinQ'] exists. + # s_vlan = traffic_param['outer_l2']['QinQ']['S-VLAN'] + # c_vlan = traffic_param['outer_l2']['QinQ']['C-VLAN'] + + self.ixnet.setMultiAttribute( + config_element + '/transmissionControl', + '-type', type, '-duration', duration) + self.ixnet.setMultiAttribute( + config_element + '/frameRate', + '-rate', rate, '-type', rate_unit) + self.ixnet.setMultiAttribute( + config_element + '/frameSize', + '-type', 'weightedPairs', + '-weightedRangePairs', weighted_range_pairs) + self.ixnet.commit() + + self._update_frame_mac( + self._get_stack_item(fg_id, PROTO_ETHERNET)[0], + 'destinationAddress', dstmac) + self._update_frame_mac( + self._get_stack_item(fg_id, PROTO_ETHERNET)[0], + 'sourceAddress', srcmac) + + def _update_ipv4_address(self, ip_descriptor, field, ip_address, seed, + mask, count): + """Set the IPv4 address in a config element stack IP field + + :param ip_descriptor: (str) IP descriptor, e.g.: + /traffic/trafficItem:1/configElement:1/stack:"ipv4-2" + :param field: (str) field name, e.g.: scrIp, dstIp + :param ip_address: (str) IP address + :param seed: (int) seed length + :param mask: (int) IP address mask length + :param count: (int) number of random IPs to generate + """ + field_descriptor = self._get_field_in_stack_item(ip_descriptor, + field) + random_mask = str(ipaddress.IPv4Address( + 2**(ipaddress.IPV4LENGTH - mask) - 1).compressed) + self.ixnet.setMultiAttribute(field_descriptor, + '-seed', seed, + '-fixedBits', ip_address, + '-randomMask', random_mask, + '-valueType', 'random', + '-countValue', count) + self.ixnet.commit() + + def update_ip_packet(self, traffic): + """Update the IP packet + + NOTE: Only IPv4 is currently supported. + :param traffic: list of traffic elements; each traffic element contains + the injection parameter for each flow group. + """ + # NOTE(ralonsoh): L4 configuration is not set. + for traffic_param in traffic.values(): + fg_id = str(traffic_param['id']) + if not self._get_config_element_by_flow_group_name(fg_id): + raise exceptions.IxNetworkFlowNotPresent(flow_group=fg_id) + + count = traffic_param['outer_l3']['count'] + srcip = str(traffic_param['outer_l3']['srcip']) + dstip = str(traffic_param['outer_l3']['dstip']) + seed = traffic_param['outer_l3']['seed'] + srcmask = traffic_param['outer_l3']['srcmask'] or IP_VERSION_4_MASK + dstmask = traffic_param['outer_l3']['dstmask'] or IP_VERSION_4_MASK + + self._update_ipv4_address( + self._get_stack_item(fg_id, PROTO_IPV4)[0], + 'srcIp', srcip, seed, srcmask, count) + self._update_ipv4_address( + self._get_stack_item(fg_id, PROTO_IPV4)[0], + 'dstIp', dstip, seed, dstmask, count) + + def update_l4(self, traffic): + """Update the L4 headers + + NOTE: Only UDP is currently supported + :param traffic: list of traffic elements; each traffic element contains + the injection parameter for each flow group + """ + for traffic_param in traffic.values(): + fg_id = str(traffic_param['id']) + if not self._get_config_element_by_flow_group_name(fg_id): + raise exceptions.IxNetworkFlowNotPresent(flow_group=fg_id) + + proto = traffic_param['outer_l3']['proto'] + if proto not in SUPPORTED_PROTO: + raise exceptions.IXIAUnsupportedProtocol(protocol=proto) + + count = traffic_param['outer_l4']['count'] + seed = traffic_param['outer_l4']['seed'] + + srcport = traffic_param['outer_l4']['srcport'] + srcmask = traffic_param['outer_l4']['srcportmask'] + + dstport = traffic_param['outer_l4']['dstport'] + dstmask = traffic_param['outer_l4']['dstportmask'] + + if proto in SUPPORTED_PROTO: + self._update_udp_port(self._get_stack_item(fg_id, proto)[0], + 'srcPort', srcport, seed, srcmask, count) + + self._update_udp_port(self._get_stack_item(fg_id, proto)[0], + 'dstPort', dstport, seed, dstmask, count) + + def _update_udp_port(self, descriptor, field, value, + seed=1, mask=0, count=1): + """Set the UDP port in a config element stack UDP field + + :param udp_descriptor: (str) UDP descriptor, e.g.: + /traffic/trafficItem:1/configElement:1/stack:"udp-3" + :param field: (str) field name, e.g.: scrPort, dstPort + :param value: (int) UDP port fixed bits + :param seed: (int) seed length + :param mask: (int) UDP port mask + :param count: (int) number of random ports to generate + """ + field_descriptor = self._get_field_in_stack_item(descriptor, field) + + if mask == 0: + seed = count = 1 + + self.ixnet.setMultiAttribute(field_descriptor, + '-auto', 'false', + '-seed', seed, + '-fixedBits', value, + '-randomMask', mask, + '-valueType', 'random', + '-countValue', count) + + self.ixnet.commit() + + def _build_stats_map(self, view_obj, name_map): + return {data_yardstick: self.ixnet.execute( + 'getColumnValues', view_obj, data_ixia) + for data_yardstick, data_ixia in name_map.items()} + + def get_statistics(self): + """Retrieve port and flow statistics + + "Port Statistics" parameters are stored in self.PORT_STATS_NAME_MAP. + "Flow Statistics" parameters are stored in self.LATENCY_NAME_MAP. + + :return: dictionary with the statistics; the keys of this dictionary + are PORT_STATS_NAME_MAP and LATENCY_NAME_MAP keys. + """ + port_statistics = '::ixNet::OBJ-/statistics/view:"Port Statistics"' + flow_statistics = '::ixNet::OBJ-/statistics/view:"Flow Statistics"' + stats = self._build_stats_map(port_statistics, + self.PORT_STATS_NAME_MAP) + stats.update(self._build_stats_map(flow_statistics, + self.LATENCY_NAME_MAP)) + return stats + + def start_traffic(self): + """Start the traffic injection in the traffic item + + By configuration, there is only one traffic item. This function returns + when the traffic state is TRAFFIC_STATUS_STARTED. + """ + traffic_items = self.ixnet.getList('/traffic', 'trafficItem') + if self.is_traffic_running(): + self.ixnet.execute('stop', '/traffic') + # pylint: disable=unnecessary-lambda + utils.wait_until_true(lambda: self.is_traffic_stopped()) + + self.ixnet.execute('generate', traffic_items) + self.ixnet.execute('apply', '/traffic') + self.ixnet.execute('start', '/traffic') + # pylint: disable=unnecessary-lambda + utils.wait_until_true(lambda: self.is_traffic_running()) diff --git a/yardstick/network_services/nfvi/resource.py b/yardstick/network_services/nfvi/resource.py index 0c0bf223a..5922bd3b9 100644 --- a/yardstick/network_services/nfvi/resource.py +++ b/yardstick/network_services/nfvi/resource.py @@ -31,6 +31,7 @@ from yardstick.common.exceptions import ResourceCommandError from yardstick.common.task_template import finalize_for_yaml from yardstick.common.utils import validate_non_string_sequence from yardstick.network_services.nfvi.collectd import AmqpConsumer +from yardstick.benchmark.contexts import heat LOG = logging.getLogger(__name__) @@ -52,7 +53,8 @@ class ResourceProfile(object): DEFAULT_TIMEOUT = 3600 OVS_SOCKET_PATH = "/usr/local/var/run/openvswitch/db.sock" - def __init__(self, mgmt, port_names=None, plugins=None, interval=None, timeout=None): + def __init__(self, mgmt, port_names=None, plugins=None, + interval=None, timeout=None, reset_mq_flag=True): if plugins is None: self.plugins = {} @@ -77,6 +79,7 @@ class ResourceProfile(object): # we need to save mgmt so we can connect to port 5672 self.mgmt = mgmt self.connection = ssh.AutoConnectSSH.from_node(mgmt) + self._reset_mq_flag = reset_mq_flag @classmethod def make_from_node(cls, node, timeout): @@ -87,7 +90,10 @@ class ResourceProfile(object): plugins = collectd_options.get("plugins", {}) interval = collectd_options.get("interval") - return cls(node, plugins=plugins, interval=interval, timeout=timeout) + reset_mq_flag = (False if node.get("ctx_type") == heat.HeatContext.__context_type__ + else True) + return cls(node, plugins=plugins, interval=interval, + timeout=timeout, reset_mq_flag=reset_mq_flag) def check_if_system_agent_running(self, process): """ verify if system agent is running """ @@ -210,11 +216,14 @@ class ResourceProfile(object): if not self.enable: return {} + if self.check_if_system_agent_running("collectd")[0] != 0: + return {} + metric = {} while not self._queue.empty(): metric.update(self._queue.get()) - msg = self.parse_collectd_result(metric) - return msg + + return self.parse_collectd_result(metric) def _provide_config_file(self, config_file_path, nfvi_cfg, template_kwargs): template = pkg_resources.resource_string("yardstick.network_services.nfvi", @@ -250,7 +259,7 @@ class ResourceProfile(object): if status != 0: LOG.error("cannot find OVS socket %s", socket_path) - def _start_rabbitmq(self, connection): + def _reset_rabbitmq(self, connection): # Reset amqp queue LOG.debug("reset and setup amqp to collect data from collectd") # ensure collectd.conf.d exists to avoid error/warning @@ -263,10 +272,37 @@ class ResourceProfile(object): "sudo rabbitmqctl authenticate_user admin admin", "sudo rabbitmqctl set_permissions -p / admin '.*' '.*' '.*'" ] + for cmd in cmd_list: - exit_status, stdout, stderr = connection.execute(cmd) - if exit_status != 0: - raise ResourceCommandError(command=cmd, stderr=stderr) + exit_status, _, stderr = connection.execute(cmd) + if exit_status != 0: + raise ResourceCommandError(command=cmd, stderr=stderr) + + def _check_rabbitmq_user(self, connection, user='admin'): + exit_status, stdout, _ = connection.execute("sudo rabbitmqctl list_users") + if exit_status == 0: + for line in stdout.split('\n')[1:]: + if line.split('\t')[0] == user: + return True + + def _set_rabbitmq_admin_user(self, connection): + LOG.debug("add admin user to amqp") + cmd_list = ["sudo rabbitmqctl add_user admin admin", + "sudo rabbitmqctl authenticate_user admin admin", + "sudo rabbitmqctl set_permissions -p / admin '.*' '.*' '.*'" + ] + + for cmd in cmd_list: + exit_status, stdout, stderr = connection.execute(cmd) + if exit_status != 0: + raise ResourceCommandError(command=cmd, stdout=stdout, stderr=stderr) + + def _start_rabbitmq(self, connection): + if self._reset_mq_flag: + self._reset_rabbitmq(connection) + else: + if not self._check_rabbitmq_user(connection): + self._set_rabbitmq_admin_user(connection) # check stdout for "sudo rabbitmqctl status" command cmd = "sudo rabbitmqctl status" @@ -282,10 +318,11 @@ class ResourceProfile(object): self._prepare_collectd_conf(config_file_path) connection.execute('sudo pkill -x -9 collectd') - exit_status = connection.execute("which %s > /dev/null 2>&1" % collectd_path)[0] + cmd = "which %s > /dev/null 2>&1" % collectd_path + exit_status, _, stderr = connection.execute(cmd) if exit_status != 0: - LOG.warning("%s is not present disabling", collectd_path) - return + raise ResourceCommandError(command=cmd, stderr=stderr) + if "ovs_stats" in self.plugins: self._setup_ovs_stats(connection) @@ -293,8 +330,12 @@ class ResourceProfile(object): LOG.debug("Start collectd service..... %s second timeout", self.timeout) # intel_pmu plug requires large numbers of files open, so try to set # ulimit -n to a large value - connection.execute("sudo bash -c 'ulimit -n 1000000 ; %s'" % collectd_path, - timeout=self.timeout) + + cmd = "sudo bash -c 'ulimit -n 1000000 ; %s'" % collectd_path + exit_status, _, stderr = connection.execute(cmd, timeout=self.timeout) + if exit_status != 0: + raise ResourceCommandError(command=cmd, stderr=stderr) + LOG.debug("Done") def initiate_systemagent(self, bin_path): @@ -334,5 +375,7 @@ class ResourceProfile(object): if pid: self.connection.execute('sudo kill -9 "%s"' % pid) self.connection.execute('sudo pkill -9 "%s"' % agent) - self.connection.execute('sudo service rabbitmq-server stop') - self.connection.execute("sudo rabbitmqctl stop_app") + + if self._reset_mq_flag: + self.connection.execute('sudo service rabbitmq-server stop') + self.connection.execute("sudo rabbitmqctl stop_app") diff --git a/yardstick/network_services/pipeline.py b/yardstick/network_services/pipeline.py index d781ba0cd..7155480d4 100644 --- a/yardstick/network_services/pipeline.py +++ b/yardstick/network_services/pipeline.py @@ -18,6 +18,8 @@ import itertools from six.moves import zip
+from yardstick.common import utils
+
FIREWALL_ADD_DEFAULT = "p {0} firewall add default 1"
FIREWALL_ADD_PRIO = """\
p {0} firewall add priority 1 ipv4 {1} 24 0.0.0.0 0 0 65535 0 65535 6 0xFF port 0"""
@@ -59,8 +61,7 @@ class PipelineRules(object): self.add_rule(FIREWALL_ADD_PRIO, ip)
def add_firewall_script(self, ip):
- ip_addr = ip.split('.')
- assert len(ip_addr) == 4
+ ip_addr = str(utils.make_ipv4_address(ip)).split('.')
ip_addr[-1] = '0'
for i in range(256):
ip_addr[-2] = str(i)
@@ -87,8 +88,7 @@ class PipelineRules(object): self.add_rule(ROUTE_ADD_ETHER_MPLS, ip, mac_addr, index)
def add_route_script(self, ip, mac_addr):
- ip_addr = ip.split('.')
- assert len(ip_addr) == 4
+ ip_addr = str(utils.make_ipv4_address(ip)).split('.')
ip_addr[-1] = '0'
for index in range(0, 256, 8):
ip_addr[-2] = str(index)
@@ -101,8 +101,7 @@ class PipelineRules(object): self.add_rule(ROUTE_ADD_ETHER_QINQ, ip, mask, mac_addr, index)
def add_route_script2(self, ip, mac_addr):
- ip_addr = ip.split('.')
- assert len(ip_addr) == 4
+ ip_addr = str(utils.make_ipv4_address(ip)).split('.')
ip_addr[-1] = '0'
mask = 24
for i in range(0, 256):
diff --git a/yardstick/network_services/traffic_profile/__init__.py b/yardstick/network_services/traffic_profile/__init__.py index 356b36bd9..a1b26a24d 100644 --- a/yardstick/network_services/traffic_profile/__init__.py +++ b/yardstick/network_services/traffic_profile/__init__.py @@ -27,6 +27,7 @@ def register_modules(): 'yardstick.network_services.traffic_profile.prox_profile', 'yardstick.network_services.traffic_profile.prox_ramp', 'yardstick.network_services.traffic_profile.rfc2544', + 'yardstick.network_services.traffic_profile.pktgen', ] for module in modules: diff --git a/yardstick/network_services/traffic_profile/base.py b/yardstick/network_services/traffic_profile/base.py index 162bab2bc..a8f950b7b 100644 --- a/yardstick/network_services/traffic_profile/base.py +++ b/yardstick/network_services/traffic_profile/base.py @@ -12,10 +12,61 @@ # See the License for the specific language governing permissions and # limitations under the License. +import re + from yardstick.common import exceptions from yardstick.common import utils +class TrafficProfileConfig(object): + """Class to contain the TrafficProfile class information + + This object will parse and validate the traffic profile information. + """ + DEFAULT_SCHEMA = 'nsb:traffic_profile:0.1' + DEFAULT_FRAME_RATE = '100' + DEFAULT_DURATION = 30 + RATE_FPS = 'fps' + RATE_PERCENTAGE = '%' + RATE_REGEX = re.compile(r'([0-9]*\.[0-9]+|[0-9]+)\s*(fps|%)*(.*)') + + def __init__(self, tp_config): + self.schema = tp_config.get('schema', self.DEFAULT_SCHEMA) + self.name = tp_config.get('name') + self.description = tp_config.get('description') + tprofile = tp_config['traffic_profile'] + self.traffic_type = tprofile.get('traffic_type') + self.frame_rate, self.rate_unit = self._parse_rate( + tprofile.get('frame_rate', self.DEFAULT_FRAME_RATE)) + self.test_precision = tprofile.get('test_precision') + self.packet_sizes = tprofile.get('packet_sizes') + self.duration = tprofile.get('duration', self.DEFAULT_DURATION) + self.lower_bound = tprofile.get('lower_bound') + self.upper_bound = tprofile.get('upper_bound') + self.step_interval = tprofile.get('step_interval') + + def _parse_rate(self, rate): + """Parse traffic profile rate + + The line rate can be defined in fps or percentage over the maximum line + rate: + - frame_rate = 5000 (by default, unit is 'fps') + - frame_rate = 5000fps + - frame_rate = 25% + + :param rate: (string, int) line rate in fps or % + :return: (tuple: int, string) line rate number and unit + """ + match = self.RATE_REGEX.match(str(rate)) + if not match: + exceptions.TrafficProfileRate() + rate = float(match.group(1)) + unit = match.group(2) if match.group(2) else self.RATE_FPS + if match.group(3): + raise exceptions.TrafficProfileRate() + return rate, unit + + class TrafficProfile(object): """ This class defines the behavior @@ -43,8 +94,9 @@ class TrafficProfile(object): # e.g. RFC2544 start_ip, stop_ip, drop_rate, # IMIX = {"10K": 0.1, "100M": 0.5} self.params = tp_config + self.config = TrafficProfileConfig(tp_config) - def execute_traffic(self, traffic_generator): + def execute_traffic(self, traffic_generator, **kawrgs): """ This methods defines the behavior of the traffic generator. It will be called in a loop until the traffic generator exits. diff --git a/yardstick/network_services/traffic_profile/http_ixload.py b/yardstick/network_services/traffic_profile/http_ixload.py index 348056551..6cbdb8ab2 100644 --- a/yardstick/network_services/traffic_profile/http_ixload.py +++ b/yardstick/network_services/traffic_profile/http_ixload.py @@ -12,9 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from __future__ import absolute_import -from __future__ import print_function - import sys import os import logging @@ -27,22 +24,14 @@ try: except ImportError: import json as jsonutils - -class ErrorClass(object): - - def __init__(self, *args, **kwargs): - if 'test' not in kwargs: - raise RuntimeError - - def __getattr__(self, item): - raise AttributeError - +from yardstick.common import exceptions try: from IxLoad import IxLoad, StatCollectorUtils except ImportError: - IxLoad = ErrorClass - StatCollectorUtils = ErrorClass + IxLoad = exceptions.ErrorClass + StatCollectorUtils = exceptions.ErrorClass + LOG = logging.getLogger(__name__) CSV_FILEPATH_NAME = 'IxL_statResults.csv' @@ -93,7 +82,7 @@ def validate_non_string_sequence(value, default=None, raise_exc=None): if isinstance(value, collections.Sequence) and not isinstance(value, str): return value if raise_exc: - raise raise_exc + raise raise_exc # pylint: disable=raising-bad-type return default @@ -218,7 +207,7 @@ class IXLOADHttpTest(object): # ---- Remap ports ---- try: self.reassign_ports(test, repository, self.ports_to_reassign) - except Exception: + except Exception: # pylint: disable=broad-except LOG.exception("Exception occurred during reassign_ports") # ----------------------------------------------------------------------- diff --git a/yardstick/network_services/traffic_profile/ixia_rfc2544.py b/yardstick/network_services/traffic_profile/ixia_rfc2544.py index 7f047226b..2086273e6 100644 --- a/yardstick/network_services/traffic_profile/ixia_rfc2544.py +++ b/yardstick/network_services/traffic_profile/ixia_rfc2544.py @@ -12,24 +12,45 @@ # See the License for the specific language governing permissions and # limitations under the License. -from __future__ import absolute_import import logging -from yardstick.network_services.traffic_profile.trex_traffic_profile import \ - TrexProfile +from yardstick.common import utils +from yardstick.network_services.traffic_profile import base as tp_base +from yardstick.network_services.traffic_profile import trex_traffic_profile + LOG = logging.getLogger(__name__) -class IXIARFC2544Profile(TrexProfile): +class IXIARFC2544Profile(trex_traffic_profile.TrexProfile): UPLINK = 'uplink' DOWNLINK = 'downlink' + DROP_PERCENT_ROUND = 6 + RATE_ROUND = 5 - def _get_ixia_traffic_profile(self, profile_data, mac=None): - if mac is None: - mac = {} + def __init__(self, yaml_data): + super(IXIARFC2544Profile, self).__init__(yaml_data) + self.rate = self.config.frame_rate + self.rate_unit = self.config.rate_unit + + def _get_ip_and_mask(self, ip_range): + _ip_range = ip_range.split('-') + if len(_ip_range) == 1: + return _ip_range[0], None + + mask = utils.get_mask_from_ip_range(_ip_range[0], _ip_range[1]) + return _ip_range[0], mask + def _get_fixed_and_mask(self, port_range): + _port_range = str(port_range).split('-') + if len(_port_range) == 1: + return int(_port_range[0]), 0 + + return int(_port_range[0]), int(_port_range[1]) + + def _get_ixia_traffic_profile(self, profile_data, mac=None): + mac = {} if mac is None else mac result = {} for traffickey, values in profile_data.items(): if not traffickey.startswith((self.UPLINK, self.DOWNLINK)): @@ -45,18 +66,25 @@ class IXIARFC2544Profile(TrexProfile): port_id = value.get('id', 1) port_index = port_id - 1 - try: - ip = value['outer_l3v6'] - except KeyError: + + if value.get('outer_l3v4'): ip = value['outer_l3v4'] src_key, dst_key = 'srcip4', 'dstip4' else: + ip = value['outer_l3v6'] src_key, dst_key = 'srcip6', 'dstip6' + srcip, srcmask = self._get_ip_and_mask(ip[src_key]) + dstip, dstmask = self._get_ip_and_mask(ip[dst_key]) + + outer_l4 = value.get('outer_l4') + src_port, src_port_mask = self._get_fixed_and_mask(outer_l4['srcport']) + dst_port, dst_port_mask = self._get_fixed_and_mask(outer_l4['dstport']) result[traffickey] = { 'bidir': False, - 'iload': '100', 'id': port_id, + 'rate': self.rate, + 'rate_unit': self.rate_unit, 'outer_l2': { 'framesize': value['outer_l2']['framesize'], 'framesPerSecond': True, @@ -67,12 +95,23 @@ class IXIARFC2544Profile(TrexProfile): 'count': ip['count'], 'dscp': ip['dscp'], 'ttl': ip['ttl'], - src_key: ip[src_key].split("-")[0], - dst_key: ip[dst_key].split("-")[0], + 'seed': ip['seed'], + 'srcip': srcip, + 'dstip': dstip, + 'srcmask': srcmask, + 'dstmask': dstmask, 'type': key, 'proto': ip['proto'], }, - 'outer_l4': value['outer_l4'], + 'outer_l4': { + 'srcport': src_port, + 'dstport': dst_port, + 'srcportmask': src_port_mask, + 'dstportmask': dst_port_mask, + 'count': outer_l4['count'], + 'seed': outer_l4['seed'], + } + } except KeyError: continue @@ -80,15 +119,10 @@ class IXIARFC2544Profile(TrexProfile): return result def _ixia_traffic_generate(self, traffic, ixia_obj): - for key, value in traffic.items(): - if key.startswith((self.UPLINK, self.DOWNLINK)): - value["iload"] = str(self.rate) - ixia_obj.ix_update_frame(traffic) - ixia_obj.ix_update_ether(traffic) - ixia_obj.add_ip_header(traffic, 4) - ixia_obj.ix_start_traffic() - self.tmp_drop = 0 - self.tmp_throughput = 0 + ixia_obj.update_frame(traffic, self.config.duration) + ixia_obj.update_ip_packet(traffic) + ixia_obj.update_l4(traffic) + ixia_obj.start_traffic() def update_traffic_profile(self, traffic_generator): def port_generator(): @@ -99,85 +133,70 @@ class IXIARFC2544Profile(TrexProfile): if not profile_data: continue self.profile_data = profile_data - self.get_streams(self.profile_data) self.full_profile.update({vld_id: self.profile_data}) for intf in intfs: yield traffic_generator.vnfd_helper.port_num(intf) self.ports = [port for port in port_generator()] - def execute_traffic(self, traffic_generator, ixia_obj, mac=None): - if mac is None: - mac = {} + def execute_traffic(self, traffic_generator, ixia_obj=None, mac=None): + mac = {} if mac is None else mac + first_run = self.first_run if self.first_run: + self.first_run = False self.full_profile = {} self.pg_id = 0 self.update_traffic_profile(traffic_generator) - traffic = \ - self._get_ixia_traffic_profile(self.full_profile, mac) self.max_rate = self.rate - self.min_rate = 0 - self.get_multiplier() - self._ixia_traffic_generate(traffic, ixia_obj) - - def get_multiplier(self): - self.rate = round((self.max_rate + self.min_rate) / 2.0, 2) - multiplier = round(self.rate / self.pps, 2) - return str(multiplier) - - def start_ixia_latency(self, traffic_generator, ixia_obj, mac=None): - if mac is None: - mac = {} - self.update_traffic_profile(traffic_generator) - traffic = \ - self._get_ixia_traffic_profile(self.full_profile, mac) + self.min_rate = 0.0 + else: + self.rate = round(float(self.max_rate + self.min_rate) / 2.0, + self.RATE_ROUND) + + traffic = self._get_ixia_traffic_profile(self.full_profile, mac) self._ixia_traffic_generate(traffic, ixia_obj) + return first_run - def get_drop_percentage(self, samples, tol_min, tolerance, ixia_obj, - mac=None): - if mac is None: - mac = {} - status = 'Running' + def get_drop_percentage(self, samples, tol_min, tolerance, + first_run=False): + completed = False drop_percent = 100 - in_packets = sum([samples[iface]['in_packets'] for iface in samples]) - out_packets = sum([samples[iface]['out_packets'] for iface in samples]) - rx_throughput = \ - sum([samples[iface]['RxThroughput'] for iface in samples]) - tx_throughput = \ - sum([samples[iface]['TxThroughput'] for iface in samples]) - packet_drop = abs(out_packets - in_packets) + num_ifaces = len(samples) + duration = self.config.duration + in_packets_sum = sum( + [samples[iface]['in_packets'] for iface in samples]) + out_packets_sum = sum( + [samples[iface]['out_packets'] for iface in samples]) + rx_throughput = sum( + [samples[iface]['RxThroughput'] for iface in samples]) + rx_throughput = round(float(rx_throughput), 2) + tx_throughput = sum( + [samples[iface]['TxThroughput'] for iface in samples]) + tx_throughput = round(float(tx_throughput), 2) + packet_drop = abs(out_packets_sum - in_packets_sum) + try: - drop_percent = round((packet_drop / float(out_packets)) * 100, 2) + drop_percent = round( + (packet_drop / float(out_packets_sum)) * 100, + self.DROP_PERCENT_ROUND) except ZeroDivisionError: LOG.info('No traffic is flowing') - samples['TxThroughput'] = round(tx_throughput / 1.0, 2) - samples['RxThroughput'] = round(rx_throughput / 1.0, 2) - samples['CurrentDropPercentage'] = drop_percent - samples['Throughput'] = self.tmp_throughput - samples['DropPercentage'] = self.tmp_drop - if drop_percent > tolerance and self.tmp_throughput == 0: - samples['Throughput'] = round(rx_throughput / 1.0, 2) - samples['DropPercentage'] = drop_percent - if self.first_run: - max_supported_rate = out_packets / 30.0 - self.rate = max_supported_rate - self.first_run = False - if drop_percent <= tolerance: - status = 'Completed' + + samples['TxThroughput'] = tx_throughput + samples['RxThroughput'] = rx_throughput + samples['DropPercentage'] = drop_percent + + if first_run: + completed = True if drop_percent <= tolerance else False + if (first_run and + self.rate_unit == tp_base.TrafficProfileConfig.RATE_FPS): + self.rate = float(out_packets_sum) / duration / num_ifaces + if drop_percent > tolerance: self.max_rate = self.rate elif drop_percent < tol_min: self.min_rate = self.rate - if drop_percent >= self.tmp_drop: - self.tmp_drop = drop_percent - self.tmp_throughput = round((rx_throughput / 1.0), 2) - samples['Throughput'] = round(rx_throughput / 1.0, 2) - samples['DropPercentage'] = drop_percent else: - samples['Throughput'] = round(rx_throughput / 1.0, 2) - samples['DropPercentage'] = drop_percent - return status, samples - self.get_multiplier() - traffic = self._get_ixia_traffic_profile(self.full_profile, mac) - self._ixia_traffic_generate(traffic, ixia_obj) - return status, samples + completed = True + + return completed, samples diff --git a/yardstick/network_services/traffic_profile/pktgen.py b/yardstick/network_services/traffic_profile/pktgen.py new file mode 100644 index 000000000..30f81b794 --- /dev/null +++ b/yardstick/network_services/traffic_profile/pktgen.py @@ -0,0 +1,61 @@ +# Copyright (c) 2018 Intel Corporation +# +# 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. + +from yardstick.common import exceptions +from yardstick.common import utils +from yardstick.network_services.traffic_profile import base as tp_base + + +class PktgenTrafficProfile(tp_base.TrafficProfile): + """This class handles Pktgen Trex Traffic profile execution""" + + def __init__(self, tp_config): # pragma: no cover + super(PktgenTrafficProfile, self).__init__(tp_config) + self._host = None + self._port = None + + def init(self, host, port): # pragma: no cover + """Initialize control parameters + + :param host: (str) ip or host name + :param port: (int) TCP socket port number for Lua commands + """ + self._host = host + self._port = port + + def start(self): + if utils.send_socket_command(self._host, self._port, + 'pktgen.start("0")') != 0: + raise exceptions.PktgenActionError(action='start') + + def stop(self): + if utils.send_socket_command(self._host, self._port, + 'pktgen.stop("0")') != 0: + raise exceptions.PktgenActionError(action='stop') + + def rate(self, rate): + command = 'pktgen.set("0", "rate", ' + str(rate) + ')' + if utils.send_socket_command(self._host, self._port, command) != 0: + raise exceptions.PktgenActionError(action='rate') + + def clear_all_stats(self): + if utils.send_socket_command(self._host, self._port, 'clr') != 0: + raise exceptions.PktgenActionError(action='clear all stats') + + def help(self): + if utils.send_socket_command(self._host, self._port, 'help') != 0: + raise exceptions.PktgenActionError(action='help') + + def execute_traffic(self, *args, **kwargs): # pragma: no cover + pass diff --git a/yardstick/network_services/traffic_profile/prox_binsearch.py b/yardstick/network_services/traffic_profile/prox_binsearch.py index 7a84f1365..9457096c8 100644 --- a/yardstick/network_services/traffic_profile/prox_binsearch.py +++ b/yardstick/network_services/traffic_profile/prox_binsearch.py @@ -21,6 +21,7 @@ import time from yardstick.network_services.traffic_profile.prox_profile import ProxProfile from yardstick.network_services import constants +from yardstick.common import constants as overall_constants LOG = logging.getLogger(__name__) @@ -84,16 +85,21 @@ class ProxBinSearchProfile(ProxProfile): # success, the binary search will complete on an integer multiple # of the precision, rather than on a fraction of it. - theor_max_thruput = 0 + theor_max_thruput = actual_max_thruput = 0 result_samples = {} + rate_samples = {} + pos_retry = 0 + neg_retry = 0 + total_retry = 0 + ok_retry = 0 # Store one time only value in influxdb single_samples = { - "test_duration" : traffic_gen.scenario_helper.scenario_cfg["runner"]["duration"], - "test_precision" : self.params["traffic_profile"]["test_precision"], - "tolerated_loss" : self.params["traffic_profile"]["tolerated_loss"], - "duration" : duration + "test_duration": traffic_gen.scenario_helper.scenario_cfg["runner"]["duration"], + "test_precision": self.params["traffic_profile"]["test_precision"], + "tolerated_loss": self.params["traffic_profile"]["tolerated_loss"], + "duration": duration } self.queue.put(single_samples) self.prev_time = time.time() @@ -102,51 +108,91 @@ class ProxBinSearchProfile(ProxProfile): 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, - line_speed) - self.curr_time = time.time() - diff_time = self.curr_time - self.prev_time - self.prev_time = self.curr_time - - if result.success: - LOG.debug("Success! Increasing lower bound") - self.current_lower = test_value - successful_pkt_loss = result.pkt_loss - samples = result.get_samples(pkt_size, successful_pkt_loss, port_samples) - - # store results with success tag in influxdb - success_samples = {'Success_' + key: value for key, value in samples.items()} - - success_samples["Success_rx_total"] = int(result.rx_total / diff_time) - success_samples["Success_tx_total"] = int(result.tx_total / diff_time) - success_samples["Success_can_be_lost"] = int(result.can_be_lost / diff_time) - success_samples["Success_drop_total"] = int(result.drop_total / diff_time) - self.queue.put(success_samples) - - # Store Actual throughput for result samples - result_samples["Result_Actual_throughput"] = \ - success_samples["Success_RxThroughput"] - else: - LOG.debug("Failure... Decreasing upper bound") - self.current_upper = test_value - samples = result.get_samples(pkt_size, successful_pkt_loss, port_samples) - - for k in samples: - tmp = samples[k] - if isinstance(tmp, dict): - for k2 in tmp: - samples[k][k2] = int(samples[k][k2] / diff_time) - - if theor_max_thruput < samples["TxThroughput"]: - theor_max_thruput = samples['TxThroughput'] - self.queue.put({'theor_max_throughput': theor_max_thruput}) - - LOG.debug("Collect TG KPIs %s %s", datetime.datetime.now(), samples) - self.queue.put(samples) + ok_retry = traffic_gen.scenario_helper.scenario_cfg["runner"].get("confirmation", 0) + for test_value in self.bounds_iterator(LOG): + pos_retry = 0 + neg_retry = 0 + total_retry = 0 + + rate_samples["MAX_Rate"] = self.current_upper + rate_samples["MIN_Rate"] = self.current_lower + rate_samples["Test_Rate"] = test_value + self.queue.put(rate_samples, True, overall_constants.QUEUE_PUT_TIMEOUT) + LOG.info("Checking MAX %s MIN %s TEST %s", + self.current_upper, self.lower_bound, test_value) + while (pos_retry <= ok_retry) and (neg_retry <= ok_retry): + + total_retry = total_retry + 1 + result, port_samples = self._profile_helper.run_test(pkt_size, duration, + test_value, + self.tolerated_loss, + line_speed) + if (total_retry > (ok_retry * 3)) and (ok_retry is not 0): + LOG.info("Failure.!! .. RETRY EXCEEDED ... decrease lower bound") + + successful_pkt_loss = result.pkt_loss + samples = result.get_samples(pkt_size, successful_pkt_loss, port_samples) + + self.current_upper = test_value + neg_retry = total_retry + elif result.success: + if (pos_retry < ok_retry) and (ok_retry is not 0): + neg_retry = 0 + LOG.info("Success! ... confirm retry") + + successful_pkt_loss = result.pkt_loss + samples = result.get_samples(pkt_size, successful_pkt_loss, port_samples) + + else: + LOG.info("Success! Increasing lower bound") + self.current_lower = test_value + + successful_pkt_loss = result.pkt_loss + samples = result.get_samples(pkt_size, successful_pkt_loss, port_samples) + + # store results with success tag in influxdb + success_samples = \ + {'Success_' + key: value for key, value in samples.items()} + + success_samples["Success_rx_total"] = int(result.rx_total) + success_samples["Success_tx_total"] = int(result.tx_total) + success_samples["Success_can_be_lost"] = int(result.can_be_lost) + success_samples["Success_drop_total"] = int(result.drop_total) + success_samples["Success_RxThroughput"] = samples["RxThroughput"] + success_samples["Success_RxThroughput_gbps"] = \ + (samples["RxThroughput"] / 1000) * ((pkt_size + 20)* 8) + LOG.info(">>>##>>Collect SUCCESS TG KPIs %s %s", + datetime.datetime.now(), success_samples) + self.queue.put(success_samples, True, overall_constants.QUEUE_PUT_TIMEOUT) + + # Store Actual throughput for result samples + actual_max_thruput = success_samples["Success_RxThroughput"] + + pos_retry = pos_retry + 1 + + else: + if (neg_retry < ok_retry) and (ok_retry is not 0): + + pos_retry = 0 + LOG.info("failure! ... confirm retry") + else: + LOG.info("Failure... Decreasing upper bound") + self.current_upper = test_value + + neg_retry = neg_retry + 1 + samples = result.get_samples(pkt_size, successful_pkt_loss, port_samples) + + if theor_max_thruput < samples["TxThroughput"]: + theor_max_thruput = samples['TxThroughput'] + self.queue.put({'theor_max_throughput': theor_max_thruput}) + + LOG.info(">>>##>>Collect TG KPIs %s %s", datetime.datetime.now(), samples) + self.queue.put(samples, True, overall_constants.QUEUE_PUT_TIMEOUT) + + LOG.info(">>>##>> Result Reached PktSize %s Theor_Max_Thruput %s Actual_throughput %s", + pkt_size, theor_max_thruput, actual_max_thruput) result_samples["Result_pktSize"] = pkt_size - result_samples["Result_theor_max_throughput"] = theor_max_thruput/ (1000 * 1000) + result_samples["Result_theor_max_throughput"] = theor_max_thruput + result_samples["Result_Actual_throughput"] = actual_max_thruput self.queue.put(result_samples) diff --git a/yardstick/network_services/traffic_profile/rfc2544.py b/yardstick/network_services/traffic_profile/rfc2544.py index 83020c85c..0e1dbd592 100644 --- a/yardstick/network_services/traffic_profile/rfc2544.py +++ b/yardstick/network_services/traffic_profile/rfc2544.py @@ -11,190 +11,288 @@ # 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. -""" RFC2544 Throughput implemenation """ -from __future__ import absolute_import -from __future__ import division import logging -from trex_stl_lib.trex_stl_client import STLStream -from trex_stl_lib.trex_stl_streams import STLFlowLatencyStats -from trex_stl_lib.trex_stl_streams import STLTXCont +from trex_stl_lib import api as Pkt +from trex_stl_lib import trex_stl_client +from trex_stl_lib import trex_stl_packet_builder_scapy +from trex_stl_lib import trex_stl_streams + +from yardstick.network_services.traffic_profile import trex_traffic_profile -from yardstick.network_services.traffic_profile.trex_traffic_profile \ - import TrexProfile LOGGING = logging.getLogger(__name__) +SRC_PORT = 'sport' +DST_PORT = 'dport' + + +class PortPgIDMap(object): + """Port and pg_id mapping class + + "pg_id" is the identification STL library gives to each stream. In the + RFC2544Profile class, the traffic has a STLProfile per port, which contains + one or several streams, one per packet size defined in the IMIX test case + description. + + Example of port <-> pg_id map: + self._port_pg_id_map = { + 0: [1, 2, 3, 4], + 1: [5, 6, 7, 8] + } + """ + + def __init__(self): + self._pg_id = 0 + self._last_port = None + self._port_pg_id_map = {} + + def add_port(self, port): + self._last_port = port + self._port_pg_id_map[port] = [] + + def get_pg_ids(self, port): + return self._port_pg_id_map.get(port, []) + + def increase_pg_id(self, port=None): + port = self._last_port if not port else port + if port is None: + return + pg_id_list = self._port_pg_id_map.get(port) + if not pg_id_list: + self.add_port(port) + pg_id_list = self._port_pg_id_map[port] + self._pg_id += 1 + pg_id_list.append(self._pg_id) + return self._pg_id -class RFC2544Profile(TrexProfile): - """ This class handles rfc2544 implemenation. """ +class RFC2544Profile(trex_traffic_profile.TrexProfile): + """TRex RFC2544 traffic profile""" + + TOLERANCE_LIMIT = 0.05 def __init__(self, traffic_generator): super(RFC2544Profile, self).__init__(traffic_generator) self.generator = None - self.max_rate = None - self.min_rate = None - self.ports = None - self.rate = 100 - self.drop_percent_at_max_tx = None - self.throughput_max = None + self.rate = self.config.frame_rate + self.max_rate = self.config.frame_rate + self.min_rate = 0 + self.drop_percent_max = 0 def register_generator(self, generator): self.generator = generator - def execute_traffic(self, traffic_generator=None): - """ Generate the stream and run traffic on the given ports """ + def stop_traffic(self, traffic_generator=None): + """"Stop traffic injection, reset counters and remove streams""" if traffic_generator is not None and self.generator is None: self.generator = traffic_generator - if self.ports is not None: - return + self.generator.client.stop() + self.generator.client.reset() + self.generator.client.remove_all_streams() + + def execute_traffic(self, traffic_generator=None): + """Generate the stream and run traffic on the given ports + + :param traffic_generator: (TrexTrafficGenRFC) traffic generator + :return ports: (list of int) indexes of ports + port_pg_id: (dict) port indexes and pg_id [1] map + [1] https://trex-tgn.cisco.com/trex/doc/cp_stl_docs/api/ + profile_code.html#stlstream-modes + """ + if traffic_generator is not None and self.generator is None: + self.generator = traffic_generator - self.ports = [] + port_pg_id = PortPgIDMap() + ports = [] for vld_id, intfs in sorted(self.generator.networks.items()): profile_data = self.params.get(vld_id) - # no profile for this port if not profile_data: continue - # correlated traffic doesn't use public traffic? - if vld_id.startswith(self.DOWNLINK) and \ - self.generator.rfc2544_helper.correlated_traffic: + if (vld_id.startswith(self.DOWNLINK) and + self.generator.rfc2544_helper.correlated_traffic): continue for intf in intfs: - port = self.generator.port_num(intf) - self.ports.append(port) - self.generator.client.add_streams(self.get_streams(profile_data), ports=port) - - self.max_rate = self.rate - self.min_rate = 0 - self.generator.client.start(ports=self.ports, mult=self.get_multiplier(), - duration=30, force=True) - self.drop_percent_at_max_tx = 0 - self.throughput_max = 0 - - def get_multiplier(self): - """ Get the rate at which next iteration to run """ - self.rate = round((self.max_rate + self.min_rate) / 2.0, 2) - multiplier = round(self.rate / self.pps, 2) - return str(multiplier) - - def get_drop_percentage(self, generator=None): - """ Calculate the drop percentage and run the traffic """ - if generator is None: - generator = self.generator - run_duration = self.generator.RUN_DURATION - samples = self.generator.generate_samples(self.ports) - - in_packets = sum([value['in_packets'] for value in samples.values()]) - out_packets = sum([value['out_packets'] for value in samples.values()]) - - packet_drop = abs(out_packets - in_packets) - drop_percent = 100.0 - try: - drop_percent = round((packet_drop / float(out_packets)) * 100, 5) - except ZeroDivisionError: - LOGGING.info('No traffic is flowing') + port_num = int(self.generator.port_num(intf)) + ports.append(port_num) + port_pg_id.add_port(port_num) + profile = self._create_profile(profile_data, + self.rate, port_pg_id) + self.generator.client.add_streams(profile, ports=[port_num]) + + self.generator.client.start(ports=ports, + duration=self.config.duration, + force=True) + return ports, port_pg_id + + def _create_profile(self, profile_data, rate, port_pg_id): + """Create a STL profile (list of streams) for a port""" + streams = [] + for packet_name in profile_data: + imix = (profile_data[packet_name]. + get('outer_l2', {}).get('framesize')) + imix_data = self._create_imix_data(imix) + self._create_vm(profile_data[packet_name]) + _streams = self._create_streams(imix_data, rate, port_pg_id) + streams.extend(_streams) + return trex_stl_streams.STLProfile(streams) + + def _create_imix_data(self, imix): + """Generate the IMIX distribution for a STL profile + + The input information is the framesize dictionary in a test case + traffic profile definition. E.g.: + downlink_0: + ipv4: + id: 2 + outer_l2: + framesize: + 64B: 10 + 128B: 20 + ... + + This function normalizes the sum of framesize weights to 100 and + returns a dictionary of frame sizes in bytes and weight in percentage. + E.g.: + imix_count = {64: 25, 128: 75} + + :param imix: (dict) IMIX size and weight + """ + imix_count = {} + if not imix: + return imix_count + + imix_count = {size.upper().replace('B', ''): int(weight) + for size, weight in imix.items()} + imix_sum = sum(imix_count.values()) + if imix_sum <= 0: + imix_count = {64: 100} + imix_sum = 100 + + weight_normalize = float(imix_sum) / 100 + return {size: float(weight) / weight_normalize + for size, weight in imix_count.items()} + + def _create_vm(self, packet_definition): + """Create the STL Raw instructions""" + self.ether_packet = Pkt.Ether() + self.ip_packet = Pkt.IP() + self.ip6_packet = None + self.udp_packet = Pkt.UDP() + self.udp[DST_PORT] = 'UDP.dport' + self.udp[SRC_PORT] = 'UDP.sport' + self.qinq = False + self.vm_flow_vars = [] + outer_l2 = packet_definition.get('outer_l2') + outer_l3v4 = packet_definition.get('outer_l3v4') + outer_l3v6 = packet_definition.get('outer_l3v6') + outer_l4 = packet_definition.get('outer_l4') + if outer_l2: + self._set_outer_l2_fields(outer_l2) + if outer_l3v4: + self._set_outer_l3v4_fields(outer_l3v4) + if outer_l3v6: + self._set_outer_l3v6_fields(outer_l3v6) + if outer_l4: + self._set_outer_l4_fields(outer_l4) + self.trex_vm = trex_stl_packet_builder_scapy.STLScVmRaw( + self.vm_flow_vars) + + def _create_single_packet(self, size=64): + size -= 4 + ether_packet = self.ether_packet + ip_packet = self.ip6_packet if self.ip6_packet else self.ip_packet + udp_packet = self.udp_packet + if self.qinq: + qinq_packet = self.qinq_packet + base_pkt = ether_packet / qinq_packet / ip_packet / udp_packet + else: + base_pkt = ether_packet / ip_packet / udp_packet + pad = max(0, size - len(base_pkt)) * 'x' + return trex_stl_packet_builder_scapy.STLPktBuilder( + pkt=base_pkt / pad, vm=self.trex_vm) + + def _create_streams(self, imix_data, rate, port_pg_id): + """Create a list of streams per packet size + + The STL TX mode speed of the generated streams will depend on the frame + weight and the frame rate. Both the frame weight and the total frame + rate are normalized to 100. The STL TX mode speed, defined in + percentage, is the combitation of both percentages. E.g.: + frame weight = 100 + rate = 90 + --> STLTXmode percentage = 10 (%) + + frame weight = 80 + rate = 50 + --> STLTXmode percentage = 40 (%) + + :param imix_data: (dict) IMIX size and weight + :param rate: (float) normalized [0..100] total weight + :param pg_id: (PortPgIDMap) port / pg_id (list) map + """ + streams = [] + for size, weight in ((int(size), float(weight)) for (size, weight) + in imix_data.items() if float(weight) > 0): + packet = self._create_single_packet(size) + pg_id = port_pg_id.increase_pg_id() + stl_flow = trex_stl_streams.STLFlowLatencyStats(pg_id=pg_id) + mode = trex_stl_streams.STLTXCont(percentage=weight * rate / 100) + streams.append(trex_stl_client.STLStream( + packet=packet, flow_stats=stl_flow, mode=mode)) + return streams + + def get_drop_percentage(self, samples, tol_low, tol_high, + correlated_traffic): + """Calculate the drop percentage and run the traffic""" + tx_rate_fps = 0 + rx_rate_fps = 0 + for sample in samples: + tx_rate_fps += sum( + port['tx_throughput_fps'] for port in sample.values()) + rx_rate_fps += sum( + port['rx_throughput_fps'] for port in sample.values()) + tx_rate_fps = round(float(tx_rate_fps) / len(samples), 2) + rx_rate_fps = round(float(rx_rate_fps) / len(samples), 2) # TODO(esm): RFC2544 doesn't tolerate packet loss, why do we? - tolerance_low = generator.rfc2544_helper.tolerance_low - tolerance_high = generator.rfc2544_helper.tolerance_high - - tx_rate = out_packets / run_duration - rx_rate = in_packets / run_duration - - throughput_max = self.throughput_max - drop_percent_at_max_tx = self.drop_percent_at_max_tx + out_packets = sum(port['out_packets'] for port in samples[-1].values()) + in_packets = sum(port['in_packets'] for port in samples[-1].values()) + drop_percent = 100.0 - if self.drop_percent_at_max_tx is None: - self.rate = tx_rate - self.first_run = False + # https://tools.ietf.org/html/rfc2544#section-26.3 + if out_packets: + drop_percent = round( + (float(abs(out_packets - in_packets)) / out_packets) * 100, 5) - if drop_percent > tolerance_high: - # TODO(esm): why don't we discard results that are out of tolerance? + tol_high = tol_high if tol_high > self.TOLERANCE_LIMIT else tol_high + tol_low = tol_low if tol_low > self.TOLERANCE_LIMIT else tol_low + if drop_percent > tol_high: self.max_rate = self.rate - if throughput_max == 0: - throughput_max = rx_rate - drop_percent_at_max_tx = drop_percent - - elif drop_percent >= tolerance_low: - # TODO(esm): why do we update the samples dict in this case - # and not update our tracking values? - throughput_max = rx_rate - drop_percent_at_max_tx = drop_percent - - elif drop_percent >= self.drop_percent_at_max_tx: - # TODO(esm): why don't we discard results that are out of tolerance? + elif drop_percent < tol_low: self.min_rate = self.rate - self.drop_percent_at_max_tx = drop_percent_at_max_tx = drop_percent - self.throughput_max = throughput_max = rx_rate + # else: + # NOTE(ralonsoh): the test should finish here + # pass + last_rate = self.rate + self.rate = round(float(self.max_rate + self.min_rate) / 2.0, 5) - else: - # TODO(esm): why don't we discard results that are out of tolerance? - self.min_rate = self.rate + throughput = rx_rate_fps * 2 if correlated_traffic else rx_rate_fps - generator.clear_client_stats(self.ports) - generator.start_client(self.ports, mult=self.get_multiplier(), - duration=run_duration, force=True) + if drop_percent > self.drop_percent_max: + self.drop_percent_max = drop_percent - # if correlated traffic update the Throughput - if generator.rfc2544_helper.correlated_traffic: - throughput_max *= 2 + latency = {port_num: value['latency'] + for port_num, value in samples[-1].items()} - samples.update({ - 'TxThroughput': tx_rate, - 'RxThroughput': rx_rate, + output = { + 'TxThroughput': tx_rate_fps, + 'RxThroughput': rx_rate_fps, 'CurrentDropPercentage': drop_percent, - 'Throughput': throughput_max, - 'DropPercentage': drop_percent_at_max_tx, - }) - - return samples - - def execute_latency(self, generator=None, samples=None): - if generator is not None and self.generator is None: - self.generator = generator - - if samples is None: - samples = self.generator.generate_samples() - - self.pps, multiplier = self.calculate_pps(samples) - self.ports = [] - self.pg_id = self.params['traffic_profile'].get('pg_id', 1) - for vld_id, intfs in sorted(self.generator.networks.items()): - profile_data = self.params.get(vld_id) - if not profile_data: - continue - # correlated traffic doesn't use public traffic? - if vld_id.startswith(self.DOWNLINK) and \ - self.generator.rfc2544_helper.correlated_traffic: - continue - for intf in intfs: - port = self.generator.port_num(intf) - self.ports.append(port) - self.generator.client.add_streams(self.get_streams(profile_data), ports=port) - - self.generator.start_client(ports=self.ports, mult=str(multiplier), - duration=120, force=True) - self.first_run = False - - def calculate_pps(self, samples): - pps = round(samples['Throughput'] / 2, 2) - multiplier = round(self.rate / self.pps, 2) - return pps, multiplier - - def create_single_stream(self, packet_size, pps, isg=0): - packet = self._create_single_packet(packet_size) - if pps: - stl_mode = STLTXCont(pps=pps) - else: - stl_mode = STLTXCont(pps=self.pps) - if self.pg_id: - LOGGING.debug("pg_id: %s", self.pg_id) - stl_flow_stats = STLFlowLatencyStats(pg_id=self.pg_id) - stream = STLStream(isg=isg, packet=packet, mode=stl_mode, - flow_stats=stl_flow_stats) - self.pg_id += 1 - else: - stream = STLStream(isg=isg, packet=packet, mode=stl_mode) - return stream + 'Throughput': throughput, + 'DropPercentage': self.drop_percent_max, + 'Rate': last_rate, + 'Latency': latency + } + return output diff --git a/yardstick/network_services/traffic_profile/trex_traffic_profile.py b/yardstick/network_services/traffic_profile/trex_traffic_profile.py index f5e3923d5..ed0355fa5 100644 --- a/yardstick/network_services/traffic_profile/trex_traffic_profile.py +++ b/yardstick/network_services/traffic_profile/trex_traffic_profile.py @@ -19,21 +19,16 @@ from random import SystemRandom import ipaddress import six - -from yardstick.common import exceptions as y_exc -from yardstick.network_services.traffic_profile import base -from trex_stl_lib.trex_stl_client import STLStream -from trex_stl_lib.trex_stl_streams import STLFlowLatencyStats -from trex_stl_lib.trex_stl_streams import STLTXCont -from trex_stl_lib.trex_stl_streams import STLProfile from trex_stl_lib.trex_stl_packet_builder_scapy import STLVmWrFlowVar from trex_stl_lib.trex_stl_packet_builder_scapy import STLVmFlowVarRepeatableRandom from trex_stl_lib.trex_stl_packet_builder_scapy import STLVmFlowVar -from trex_stl_lib.trex_stl_packet_builder_scapy import STLPktBuilder -from trex_stl_lib.trex_stl_packet_builder_scapy import STLScVmRaw from trex_stl_lib.trex_stl_packet_builder_scapy import STLVmFixIpv4 from trex_stl_lib import api as Pkt +from yardstick.common import exceptions as y_exc +from yardstick.network_services.traffic_profile import base + + SRC = 'src' DST = 'dst' ETHERNET = 'Ethernet' @@ -342,115 +337,6 @@ class TrexProfile(base.TrafficProfile): if 'dstport' in outer_l4: self._set_proto_addr(UDP, DST_PORT, outer_l4['dstport'], outer_l4['count']) - def generate_imix_data(self, packet_definition): - """ generate packet size for a given traffic profile """ - imix_count = {} - imix_data = {} - if not packet_definition: - return imix_count - imix = packet_definition.get('framesize') - if imix: - for size in imix: - data = imix[size] - imix_data[int(size[:-1])] = int(data) - imix_sum = sum(imix_data.values()) - if imix_sum > 100: - raise SystemExit("Error in IMIX data") - elif imix_sum < 100: - imix_data[64] = imix_data.get(64, 0) + (100 - imix_sum) - - avg_size = 0.0 - for size in imix_data: - count = int(imix_data[size]) - if count: - avg_size += round(size * count / 100, 2) - pps = round(self.pps * count / 100, 0) - imix_count[size] = pps - self.rate = round(1342177280 / avg_size, 0) * 2 - logging.debug("Imax: %s rate: %s", imix_count, self.rate) - return imix_count - - def get_streams(self, profile_data): - """ generate trex stream - :param profile_data: - :type profile_data: - """ - self.streams = [] - self.pps = self.params['traffic_profile'].get('frame_rate', 100) - for packet_name in profile_data: - outer_l2 = profile_data[packet_name].get('outer_l2') - imix_data = self.generate_imix_data(outer_l2) - if not imix_data: - imix_data = {64: self.pps} - self.generate_vm(profile_data[packet_name]) - for size in imix_data: - self._generate_streams(size, imix_data[size]) - self._generate_profile() - return self.profile - - def generate_vm(self, packet_definition): - """ generate trex vm with flows setup """ - self.ether_packet = Pkt.Ether() - self.ip_packet = Pkt.IP() - self.ip6_packet = None - self.udp_packet = Pkt.UDP() - self.udp[DST_PORT] = 'UDP.dport' - self.udp[SRC_PORT] = 'UDP.sport' - self.qinq = False - self.vm_flow_vars = [] - outer_l2 = packet_definition.get('outer_l2', None) - outer_l3v4 = packet_definition.get('outer_l3v4', None) - outer_l3v6 = packet_definition.get('outer_l3v6', None) - outer_l4 = packet_definition.get('outer_l4', None) - if outer_l2: - self._set_outer_l2_fields(outer_l2) - if outer_l3v4: - self._set_outer_l3v4_fields(outer_l3v4) - if outer_l3v6: - self._set_outer_l3v6_fields(outer_l3v6) - if outer_l4: - self._set_outer_l4_fields(outer_l4) - self.trex_vm = STLScVmRaw(self.vm_flow_vars) - - def generate_packets(self): - """ generate packets from trex TG """ - base_pkt = self.base_pkt - size = self.fsize - 4 - pad = max(0, size - len(base_pkt)) * 'x' - self.packets = [STLPktBuilder(pkt=base_pkt / pad, - vm=vm) for vm in self.vms] - - def _create_single_packet(self, size=64): - size = size - 4 - ether_packet = self.ether_packet - ip_packet = self.ip6_packet if self.ip6_packet else self.ip_packet - udp_packet = self.udp_packet - if self.qinq: - qinq_packet = self.qinq_packet - base_pkt = ether_packet / qinq_packet / ip_packet / udp_packet - else: - base_pkt = ether_packet / ip_packet / udp_packet - pad = max(0, size - len(base_pkt)) * 'x' - packet = STLPktBuilder(pkt=base_pkt / pad, vm=self.trex_vm) - return packet - - def _create_single_stream(self, packet_size, pps, isg=0): - packet = self._create_single_packet(packet_size) - if self.pg_id: - self.pg_id += 1 - stl_flow = STLFlowLatencyStats(pg_id=self.pg_id) - stream = STLStream(isg=isg, packet=packet, mode=STLTXCont(pps=pps), - flow_stats=stl_flow) - else: - stream = STLStream(isg=isg, packet=packet, mode=STLTXCont(pps=pps)) - return stream - - def _generate_streams(self, packet_size, pps): - self.streams.append(self._create_single_stream(packet_size, pps)) - - def _generate_profile(self): - self.profile = STLProfile(self.streams) - @classmethod def _count_ip(cls, start_ip, end_ip): start = ipaddress.ip_address(six.u(start_ip)) diff --git a/yardstick/network_services/vnf_generic/vnf/acl_vnf.py b/yardstick/network_services/vnf_generic/vnf/acl_vnf.py index f3cafef7a..11a602472 100644 --- a/yardstick/network_services/vnf_generic/vnf/acl_vnf.py +++ b/yardstick/network_services/vnf_generic/vnf/acl_vnf.py @@ -13,16 +13,20 @@ # limitations under the License. import logging - +import ipaddress +import six from yardstick.common import utils +from yardstick.common import exceptions + from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNF, DpdkVnfSetupEnvHelper -from yardstick.network_services.yang_model import YangModel +from yardstick.network_services.helpers.samplevnf_helper import PortPairs +from itertools import chain LOG = logging.getLogger(__name__) # ACL should work the same on all systems, we can provide the binary ACL_PIPELINE_COMMAND = \ - 'sudo {tool_path} -p {port_mask_hex} -f {cfg_file} -s {script}' + 'sudo {tool_path} -p {port_mask_hex} -f {cfg_file} -s {script} {hwlb}' ACL_COLLECT_KPI = r"""\ ACL TOTAL:[^p]+pkts_processed"?:\s(\d+),[^p]+pkts_drop"?:\s(\d+),[^p]+pkts_received"?:\s(\d+),""" @@ -38,6 +42,196 @@ class AclApproxSetupEnvSetupEnvHelper(DpdkVnfSetupEnvHelper): SW_DEFAULT_CORE = 5 DEFAULT_CONFIG_TPL_CFG = "acl.cfg" VNF_TYPE = "ACL" + RULE_CMD = "acl" + + DEFAULT_PRIORITY = 1 + DEFAULT_PROTOCOL = 0 + DEFAULT_PROTOCOL_MASK = 0 + # Default actions to be applied to SampleVNF. Please note, + # that this list is extended with `fwd` action when default + # actions are generated. + DEFAULT_FWD_ACTIONS = ["accept", "count"] + + def __init__(self, vnfd_helper, ssh_helper, scenario_helper): + super(AclApproxSetupEnvSetupEnvHelper, self).__init__(vnfd_helper, + ssh_helper, + scenario_helper) + self._action_id = 0 + + def get_ip_from_port(self, port): + # we can't use gateway because in OpenStack gateways interfere with floating ip routing + # return self.make_ip_addr(self.get_ports_gateway(port), self.get_netmask_gateway(port)) + vintf = self.vnfd_helper.find_interface(name=port)["virtual-interface"] + return utils.make_ip_addr(vintf["local_ip"], vintf["netmask"]) + + def get_network_and_prefixlen_from_ip_of_port(self, port): + ip_addr = self.get_ip_from_port(port) + # handle cases with no gateway + if ip_addr: + return ip_addr.network.network_address.exploded, ip_addr.network.prefixlen + else: + return None, None + + @property + def new_action_id(self): + """Get new action id""" + self._action_id += 1 + return self._action_id + + def get_default_flows(self): + """Get default actions/rules + Returns: (<actions>, <rules>) + <actions>: + { <action_id>: [ <list of actions> ]} + Example: + { 0 : [ "accept", "count", {"fwd" : "port": 0} ], ... } + <rules>: + [ {"src_ip": "x.x.x.x", "src_ip_mask", 24, ...}, ... ] + Note: + See `generate_rule_cmds()` to get list of possible map keys. + """ + actions, rules = {}, [] + _port_pairs = PortPairs(self.vnfd_helper.interfaces) + port_pair_list = _port_pairs.port_pair_list + for src_intf, dst_intf in port_pair_list: + # get port numbers of the interfaces + src_port = self.vnfd_helper.port_num(src_intf) + dst_port = self.vnfd_helper.port_num(dst_intf) + # get interface addresses and prefixes + src_net, src_prefix_len = self.get_network_and_prefixlen_from_ip_of_port(src_intf) + dst_net, dst_prefix_len = self.get_network_and_prefixlen_from_ip_of_port(dst_intf) + # ignore entries with empty values + if all((src_net, src_prefix_len, dst_net, dst_prefix_len)): + # flow: src_net:dst_net -> dst_port + action_id = self.new_action_id + actions[action_id] = self.DEFAULT_FWD_ACTIONS[:] + actions[action_id].append({"fwd": {"port": dst_port}}) + rules.append({"priority": 1, 'cmd': self.RULE_CMD, + "src_ip": src_net, "src_ip_mask": src_prefix_len, + "dst_ip": dst_net, "dst_ip_mask": dst_prefix_len, + "src_port_from": 0, "src_port_to": 65535, + "dst_port_from": 0, "dst_port_to": 65535, + "protocol": 0, "protocol_mask": 0, + "action_id": action_id}) + # flow: dst_net:src_net -> src_port + action_id = self.new_action_id + actions[action_id] = self.DEFAULT_FWD_ACTIONS[:] + actions[action_id].append({"fwd": {"port": src_port}}) + rules.append({"cmd":self.RULE_CMD, "priority": 1, + "src_ip": dst_net, "src_ip_mask": dst_prefix_len, + "dst_ip": src_net, "dst_ip_mask": src_prefix_len, + "src_port_from": 0, "src_port_to": 65535, + "dst_port_from": 0, "dst_port_to": 65535, + "protocol": 0, "protocol_mask": 0, + "action_id": action_id}) + return actions, rules + + def get_flows(self, options): + """Get actions/rules based on provided options. + The `options` is a dict representing the ACL rules configuration + file. Result is the same as described in `get_default_flows()`. + """ + actions, rules = {}, [] + for ace in options['access-list-entries']: + # Generate list of actions + action_id = self.new_action_id + actions[action_id] = ace['actions'] + # Destination nestwork + matches = ace['matches'] + dst_ipv4_net = matches['destination-ipv4-network'] + dst_ipv4_net_ip = ipaddress.ip_interface(six.text_type(dst_ipv4_net)) + # Source network + src_ipv4_net = matches['source-ipv4-network'] + src_ipv4_net_ip = ipaddress.ip_interface(six.text_type(src_ipv4_net)) + # Append the rule + rules.append({'action_id': action_id, 'cmd': self.RULE_CMD, + 'dst_ip': dst_ipv4_net_ip.network.network_address.exploded, + 'dst_ip_mask': dst_ipv4_net_ip.network.prefixlen, + 'src_ip': src_ipv4_net_ip.network.network_address.exploded, + 'src_ip_mask': src_ipv4_net_ip.network.prefixlen, + 'dst_port_from': matches['destination-port-range']['lower-port'], + 'dst_port_to': matches['destination-port-range']['upper-port'], + 'src_port_from': matches['source-port-range']['lower-port'], + 'src_port_to': matches['source-port-range']['upper-port'], + 'priority': matches.get('priority', self.DEFAULT_PRIORITY), + 'protocol': matches.get('protocol', self.DEFAULT_PROTOCOL), + 'protocol_mask': matches.get('protocol_mask', + self.DEFAULT_PROTOCOL_MASK) + }) + return actions, rules + + def generate_rule_cmds(self, rules, apply_rules=False): + """Convert rules into list of SampleVNF CLI commands""" + rule_template = ("p {cmd} add {priority} {src_ip} {src_ip_mask} " + "{dst_ip} {dst_ip_mask} {src_port_from} {src_port_to} " + "{dst_port_from} {dst_port_to} {protocol} " + "{protocol_mask} {action_id}") + rule_cmd_list = [] + for rule in rules: + rule_cmd_list.append(rule_template.format(**rule)) + if apply_rules: + # add command to apply all rules at the end + rule_cmd_list.append("p {cmd} applyruleset".format(cmd=self.RULE_CMD)) + return rule_cmd_list + + def generate_action_cmds(self, actions): + """Convert actions into list of SampleVNF CLI commands. + These method doesn't validate the provided list of actions. Supported + list of actions are limited by SampleVNF. Thus, the user should be + responsible to specify correct action name(s). Yardstick should take + the provided action by user and apply it to SampleVNF. + Anyway, some of the actions require addition parameters to be + specified. In case of `fwd` & `nat` action used have to specify + the port attribute. + """ + _action_template_map = { + "fwd": "p action add {action_id} fwd {port}", + "nat": "p action add {action_id} nat {port}" + } + action_cmd_list = [] + for action_id, actions in actions.items(): + for action in actions: + if isinstance(action, dict): + for action_name in action.keys(): + # user provided an action name with addition options + # e.g.: {"fwd": {"port": 0}} + # format action CLI command and add it to the list + if action_name not in _action_template_map.keys(): + raise exceptions.AclUnknownActionTemplate( + action_name=action_name) + template = _action_template_map[action_name] + try: + action_cmd_list.append(template.format( + action_id=action_id, **action[action_name])) + except KeyError as exp: + raise exceptions.AclMissingActionArguments( + action_name=action_name, + action_param=exp.args[0]) + else: + # user provided an action name w/o addition options + # e.g.: "accept", "count" + action_cmd_list.append( + "p action add {action_id} {action}".format( + action_id=action_id, action=action)) + return action_cmd_list + + def get_flows_config(self, options=None): + """Get action/rules configuration commands (string) to be + applied to SampleVNF to configure ACL rules (flows). + """ + action_cmd_list, rule_cmd_list = [], [] + if options: + # if file name is set, read actions/rules from the file + actions, rules = self.get_flows(options) + action_cmd_list = self.generate_action_cmds(actions) + rule_cmd_list = self.generate_rule_cmds(rules) + # default actions/rules + dft_actions, dft_rules = self.get_default_flows() + dft_action_cmd_list = self.generate_action_cmds(dft_actions) + dft_rule_cmd_list = self.generate_rule_cmds(dft_rules, apply_rules=True) + # generate multi-line commands to add actions/rules + return '\n'.join(chain(action_cmd_list, dft_action_cmd_list, + rule_cmd_list, dft_rule_cmd_list)) class AclApproxVnf(SampleVNF): @@ -52,17 +246,9 @@ class AclApproxVnf(SampleVNF): 'packets_dropped': 2, } - def __init__(self, name, vnfd, setup_env_helper_type=None, resource_helper_type=None): + def __init__(self, name, vnfd, task_id, setup_env_helper_type=None, + resource_helper_type=None): if setup_env_helper_type is None: setup_env_helper_type = AclApproxSetupEnvSetupEnvHelper - - super(AclApproxVnf, self).__init__(name, vnfd, setup_env_helper_type, resource_helper_type) - self.acl_rules = None - - def _start_vnf(self): - yang_model_path = utils.find_relative_file( - self.scenario_helper.options['rules'], - self.scenario_helper.task_path) - yang_model = YangModel(yang_model_path) - self.acl_rules = yang_model.get_rules() - super(AclApproxVnf, self)._start_vnf() + super(AclApproxVnf, self).__init__( + name, vnfd, task_id, setup_env_helper_type, resource_helper_type) diff --git a/yardstick/network_services/vnf_generic/vnf/base.py b/yardstick/network_services/vnf_generic/vnf/base.py index 9ceac3167..0fb310075 100644 --- a/yardstick/network_services/vnf_generic/vnf/base.py +++ b/yardstick/network_services/vnf_generic/vnf/base.py @@ -11,13 +11,16 @@ # 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. -""" Base class implementation for generic vnf implementation """ import abc import logging import six +from yardstick.common import messaging +from yardstick.common.messaging import consumer +from yardstick.common.messaging import payloads +from yardstick.common.messaging import producer from yardstick.network_services.helpers.samplevnf_helper import PortPairs @@ -138,6 +141,70 @@ class VnfdHelper(dict): yield port_name, port_num +class TrafficGeneratorProducer(producer.MessagingProducer): + """Class implementing the message producer for traffic generators + + This message producer must be instantiated in the process created + "run_traffic" process. + """ + def __init__(self, _id): + super(TrafficGeneratorProducer, self).__init__(messaging.TOPIC_TG, + _id=_id) + + def tg_method_started(self, version=1): + """Send a message to inform the traffic generation has started""" + self.send_message( + messaging.TG_METHOD_STARTED, + payloads.TrafficGeneratorPayload(version=version, iteration=0, + kpi={})) + + def tg_method_finished(self, version=1): + """Send a message to inform the traffic generation has finished""" + self.send_message( + messaging.TG_METHOD_FINISHED, + payloads.TrafficGeneratorPayload(version=version, iteration=0, + kpi={})) + + def tg_method_iteration(self, iteration, version=1, kpi=None): + """Send a message, with KPI, once an iteration has finished""" + kpi = {} if kpi is None else kpi + self.send_message( + messaging.TG_METHOD_ITERATION, + payloads.TrafficGeneratorPayload(version=version, + iteration=iteration, kpi=kpi)) + + +@six.add_metaclass(abc.ABCMeta) +class GenericVNFEndpoint(consumer.NotificationHandler): + """Endpoint class for ``GenericVNFConsumer``""" + + @abc.abstractmethod + def runner_method_start_iteration(self, ctxt, **kwargs): + """Endpoint when RUNNER_METHOD_START_ITERATION is received + + :param ctxt: (dict) {'id': <Producer ID>} + :param kwargs: (dict) ``payloads.RunnerPayload`` context + """ + + @abc.abstractmethod + def runner_method_stop_iteration(self, ctxt, **kwargs): + """Endpoint when RUNNER_METHOD_STOP_ITERATION is received + + :param ctxt: (dict) {'id': <Producer ID>} + :param kwargs: (dict) ``payloads.RunnerPayload`` context + """ + + +class GenericVNFConsumer(consumer.MessagingConsumer): + """MQ consumer for ``GenericVNF`` derived classes""" + + def __init__(self, ctx_ids, endpoints): + if not isinstance(endpoints, list): + endpoints = [endpoints] + super(GenericVNFConsumer, self).__init__(messaging.TOPIC_RUNNER, + ctx_ids, endpoints) + + @six.add_metaclass(abc.ABCMeta) class GenericVNF(object): """Class providing file-like API for generic VNF implementation @@ -150,8 +217,9 @@ class GenericVNF(object): UPLINK = PortPairs.UPLINK DOWNLINK = PortPairs.DOWNLINK - def __init__(self, name, vnfd): + def __init__(self, name, vnfd, task_id): self.name = name + self._task_id = task_id self.vnfd_helper = VnfdHelper(vnfd) # List of statistics we can obtain from this VNF # - ETSI MANO 6.3.1.1 monitoring_parameter @@ -210,12 +278,13 @@ class GenericVNF(object): @six.add_metaclass(abc.ABCMeta) class GenericTrafficGen(GenericVNF): - """ Class providing file-like API for generic traffic generator """ + """Class providing file-like API for generic traffic generator""" - def __init__(self, name, vnfd): - super(GenericTrafficGen, self).__init__(name, vnfd) + def __init__(self, name, vnfd, task_id): + super(GenericTrafficGen, self).__init__(name, vnfd, task_id) self.runs_traffic = True self.traffic_finished = False + self._mq_producer = None @abc.abstractmethod def run_traffic(self, traffic_profile): @@ -286,3 +355,16 @@ class GenericTrafficGen(GenericVNF): :return: True/False """ pass + + @staticmethod + def _setup_mq_producer(id): + """Setup the TG MQ producer to send messages between processes + + :return: (derived class from ``MessagingProducer``) MQ producer object + """ + return TrafficGeneratorProducer(id) + + def get_mq_producer_id(self): + """Return the MQ producer ID if initialized""" + if self._mq_producer: + return self._mq_producer.id diff --git a/yardstick/network_services/vnf_generic/vnf/cgnapt_vnf.py b/yardstick/network_services/vnf_generic/vnf/cgnapt_vnf.py index 53f73b4d7..14f1e2e97 100644 --- a/yardstick/network_services/vnf_generic/vnf/cgnapt_vnf.py +++ b/yardstick/network_services/vnf_generic/vnf/cgnapt_vnf.py @@ -21,10 +21,10 @@ from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNF, Dpd LOG = logging.getLogger(__name__) # CGNAPT should work the same on all systems, we can provide the binary -CGNAPT_PIPELINE_COMMAND = 'sudo {tool_path} -p {port_mask_hex} -f {cfg_file} -s {script}' +CGNAPT_PIPELINE_COMMAND = 'sudo {tool_path} -p {port_mask_hex} -f {cfg_file} -s {script} {hwlb}' WAIT_FOR_STATIC_NAPT = 4 -CGNAPT_COLLECT_KPI = """\ +CGNAPT_COLLECT_KPI = r"""\ CG-NAPT(.*\n)*\ Received\s(\d+),\ Missed\s(\d+),\ @@ -85,12 +85,12 @@ class CgnaptApproxVnf(SampleVNF): "packets_dropped": 4, } - def __init__(self, name, vnfd, setup_env_helper_type=None, resource_helper_type=None): + def __init__(self, name, vnfd, task_id, setup_env_helper_type=None, + resource_helper_type=None): if setup_env_helper_type is None: setup_env_helper_type = CgnaptApproxSetupEnvHelper - - super(CgnaptApproxVnf, self).__init__(name, vnfd, setup_env_helper_type, - resource_helper_type) + super(CgnaptApproxVnf, self).__init__( + name, vnfd, task_id, setup_env_helper_type, resource_helper_type) def _vnf_up_post(self): super(CgnaptApproxVnf, self)._vnf_up_post() diff --git a/yardstick/network_services/vnf_generic/vnf/prox_helpers.py b/yardstick/network_services/vnf_generic/vnf/prox_helpers.py index 31ed30140..3241719e8 100644 --- a/yardstick/network_services/vnf_generic/vnf/prox_helpers.py +++ b/yardstick/network_services/vnf_generic/vnf/prox_helpers.py @@ -44,6 +44,8 @@ SECTION_CONTENTS = 1 LOG = logging.getLogger(__name__) LOG.setLevel(logging.DEBUG) +LOG_RESULT = logging.getLogger('yardstick') +LOG_RESULT.setLevel(logging.DEBUG) BITS_PER_BYTE = 8 RETRY_SECONDS = 60 @@ -123,7 +125,8 @@ class TotStatsTuple(namedtuple('TotStats', 'rx,tx,tsc,hz')): class ProxTestDataTuple(namedtuple('ProxTestDataTuple', 'tolerated,tsc_hz,delta_rx,' 'delta_tx,delta_tsc,' - 'latency,rx_total,tx_total,pps')): + 'latency,rx_total,tx_total,' + 'requested_pps')): @property def pkt_loss(self): try: @@ -132,11 +135,16 @@ class ProxTestDataTuple(namedtuple('ProxTestDataTuple', 'tolerated,tsc_hz,delta_ return 100.0 @property - def mpps(self): + def tx_mpps(self): # calculate the effective throughput in Mpps return float(self.delta_tx) * self.tsc_hz / self.delta_tsc / 1e6 @property + def rx_mpps(self): + # calculate the effective throughput in Mpps + return float(self.delta_rx) * self.tsc_hz / self.delta_tsc / 1e6 + + @property def can_be_lost(self): return int(self.tx_total * self.tolerated / 1e2) @@ -162,11 +170,12 @@ class ProxTestDataTuple(namedtuple('ProxTestDataTuple', 'tolerated,tsc_hz,delta_ ] samples = { - "Throughput": self.mpps, + "Throughput": self.rx_mpps, + "RxThroughput": self.rx_mpps, "DropPackets": pkt_loss, "CurrentDropPackets": pkt_loss, - "TxThroughput": self.pps / 1e6, - "RxThroughput": self.mpps, + "RequestedTxThroughput": self.requested_pps / 1e6, + "TxThroughput": self.tx_mpps, "PktSize": pkt_size, } if port_samples: @@ -177,11 +186,12 @@ class ProxTestDataTuple(namedtuple('ProxTestDataTuple', 'tolerated,tsc_hz,delta_ def log_data(self, logger=None): if logger is None: - logger = LOG + logger = LOG_RESULT template = "RX: %d; TX: %d; dropped: %d (tolerated: %d)" - logger.debug(template, self.rx_total, self.tx_total, self.drop_total, self.can_be_lost) - logger.debug("Mpps configured: %f; Mpps effective %f", self.pps / 1e6, self.mpps) + logger.info(template, self.rx_total, self.tx_total, self.drop_total, self.can_be_lost) + logger.info("Mpps configured: %f; Mpps generated %f; Mpps received %f", + self.requested_pps / 1e6, self.tx_mpps, self.rx_mpps) class PacketDump(object): @@ -288,7 +298,7 @@ class ProxSocketHelper(object): if mode != 'pktdump': # Regular 1-line message. Stop reading from the socket. LOG.debug("Regular response read") - return ret_str + return ret_str, True LOG.debug("Packet dump header read: [%s]", ret_str) @@ -309,13 +319,13 @@ class ProxSocketHelper(object): # Return boolean instead of string to signal # successful reception of the packet dump. LOG.debug("Packet dump stored, returning") - return True + return True, False index = data_end + 1 - return ret_str + return ret_str, False - def get_data(self, pkt_dump_only=False, timeout=1): + def get_data(self, pkt_dump_only=False, timeout=0.01): """ read data from the socket """ # This method behaves slightly differently depending on whether it is @@ -352,7 +362,9 @@ class ProxSocketHelper(object): ret_str = "" for status in iter(is_ready, False): decoded_data = self._sock.recv(256).decode('utf-8') - ret_str = self._parse_socket_data(decoded_data, pkt_dump_only) + ret_str, done = self._parse_socket_data(decoded_data, pkt_dump_only) + if (done): + break LOG.debug("Received data from socket: [%s]", ret_str) return ret_str if status else '' @@ -386,8 +398,14 @@ class ProxSocketHelper(object): def stop(self, cores, task=''): """ stop specific cores on the remote instance """ - LOG.debug("Stopping cores %s", cores) - self.put_command("stop {} {}\n".format(join_non_strings(',', cores), task)) + + tmpcores = [] + for core in cores: + if core not in tmpcores: + tmpcores.append(core) + + LOG.debug("Stopping cores %s", tmpcores) + self.put_command("stop {} {}\n".format(join_non_strings(',', tmpcores), task)) time.sleep(3) def start_all(self): @@ -397,8 +415,14 @@ class ProxSocketHelper(object): def start(self, cores): """ start specific cores on the remote instance """ - LOG.debug("Starting cores %s", cores) - self.put_command("start {}\n".format(join_non_strings(',', cores))) + + tmpcores = [] + for core in cores: + if core not in tmpcores: + tmpcores.append(core) + + LOG.debug("Starting cores %s", tmpcores) + self.put_command("start {}\n".format(join_non_strings(',', tmpcores))) time.sleep(3) def reset_stats(self): @@ -520,6 +544,51 @@ class ProxSocketHelper(object): tsc = int(ret[3]) return rx, tx, drop, tsc + def multi_port_stats(self, ports): + """get counter values from all ports port""" + + ports_str = "" + for port in ports: + ports_str = ports_str + str(port) + "," + ports_str = ports_str[:-1] + + ports_all_data = [] + tot_result = [0] * len(ports) + + retry_counter = 0 + port_index = 0 + while (len(ports) is not len(ports_all_data)) and (retry_counter < 10): + self.put_command("multi port stats {}\n".format(ports_str)) + ports_all_data = self.get_data().split(";") + + if len(ports) is len(ports_all_data): + for port_data_str in ports_all_data: + + try: + tot_result[port_index] = [try_int(s, 0) for s in port_data_str.split(",")] + except (IndexError, TypeError): + LOG.error("Port Index error %d %s - retrying ", port_index, port_data_str) + + if (len(tot_result[port_index]) is not 6) or \ + tot_result[port_index][0] is not ports[port_index]: + ports_all_data = [] + tot_result = [0] * len(ports) + port_index = 0 + time.sleep(0.1) + LOG.error("Corrupted PACKET %s - retrying", port_data_str) + break + else: + port_index = port_index + 1 + else: + LOG.error("Empty / too much data - retry -%s-", ports_all_data) + ports_all_data = [] + tot_result = [0] * len(ports) + port_index = 0 + time.sleep(0.1) + + retry_counter = retry_counter + 1 + return tot_result + def port_stats(self, ports): """get counter values from a specific port""" tot_result = [0] * 12 @@ -900,7 +969,7 @@ class ProxResourceHelper(ClientResourceHelper): self._test_type = self.setup_helper.find_in_section('global', 'name', None) return self._test_type - def run_traffic(self, traffic_profile): + def run_traffic(self, traffic_profile, *args): self._queue.cancel_join_thread() self.lower = 0.0 self.upper = 100.0 @@ -1000,9 +1069,13 @@ class ProxDataHelper(object): @property def totals_and_pps(self): if self._totals_and_pps is None: - rx_total, tx_total = self.sut.port_stats(range(self.port_count))[6:8] - pps = self.value / 100.0 * self.line_rate_to_pps() - self._totals_and_pps = rx_total, tx_total, pps + rx_total = tx_total = 0 + all_ports = self.sut.multi_port_stats(range(self.port_count)) + for port in all_ports: + rx_total = rx_total + port[1] + tx_total = tx_total + port[2] + requested_pps = self.value / 100.0 * self.line_rate_to_pps() + self._totals_and_pps = rx_total, tx_total, requested_pps return self._totals_and_pps @property @@ -1014,25 +1087,24 @@ class ProxDataHelper(object): return self.totals_and_pps[1] @property - def pps(self): + def requested_pps(self): return self.totals_and_pps[2] @property def samples(self): samples = {} + ports = [] + port_names = [] for port_name, port_num in self.vnfd_helper.ports_iter(): - try: - port_rx_total, port_tx_total = self.sut.port_stats([port_num])[6:8] - samples[port_name] = { - "in_packets": port_rx_total, - "out_packets": port_tx_total, - } - except (KeyError, TypeError, NameError, MemoryError, ValueError, - SystemError, BufferError): - samples[port_name] = { - "in_packets": 0, - "out_packets": 0, - } + ports.append(port_num) + port_names.append(port_name) + + results = self.sut.multi_port_stats(ports) + for result in results: + port_num = result[0] + samples[port_names[port_num]] = { + "in_packets": result[1], + "out_packets": result[2]} return samples def __enter__(self): @@ -1055,7 +1127,7 @@ class ProxDataHelper(object): self.latency, self.rx_total, self.tx_total, - self.pps, + self.requested_pps, ) self.result_tuple.log_data() @@ -1134,6 +1206,7 @@ class ProxProfileHelper(object): self.sut.set_pkt_size(self.test_cores, pkt_size) self.sut.set_speed(self.test_cores, value) self.sut.start_all() + time.sleep(1) yield finally: self.sut.stop_all() @@ -1153,12 +1226,32 @@ class ProxProfileHelper(object): return cores + def pct_10gbps(self, percent, line_speed): + """Get rate in percent of 10 Gbps. + + Returns the rate in percent of 10 Gbps. + For instance 100.0 = 10 Gbps; 400.0 = 40 Gbps. + + This helper method isrequired when setting interface_speed option in + the testcase because NSB/PROX considers 10Gbps as 100% of line rate, + this means that the line rate must be expressed as a percentage of + 10Gbps. + + :param percent: (float) Percent of line rate (100.0 = line rate). + :param line_speed: (int) line rate speed, in bits per second. + + :return: (float) Represents the rate in percent of 10Gbps. + """ + return (percent * line_speed / ( + constants.ONE_GIGABIT_IN_BITS * constants.NIC_GBPS_DEFAULT)) + 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, self.traffic_context(pkt_size, + self.pct_10gbps(value, line_speed)): with data_helper.measure_tot_stats(): time.sleep(duration) # Getting statistics to calculate PPS at right speed.... @@ -1246,6 +1339,7 @@ class ProxMplsProfileHelper(ProxProfileHelper): ratio = 1.0 * (pkt_size - 4 + 20) / (pkt_size + 20) self.sut.set_speed(self.plain_cores, value * ratio) self.sut.start_all() + time.sleep(1) yield finally: self.sut.stop_all() @@ -1417,7 +1511,8 @@ class ProxBngProfileHelper(ProxProfileHelper): 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, self.traffic_context(pkt_size, + self.pct_10gbps(value, line_speed)): with data_helper.measure_tot_stats(): time.sleep(duration) # Getting statistics to calculate PPS at right speed.... @@ -1606,7 +1701,8 @@ class ProxVpeProfileHelper(ProxProfileHelper): 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, self.traffic_context(pkt_size, + self.pct_10gbps(value, line_speed)): with data_helper.measure_tot_stats(): time.sleep(duration) # Getting statistics to calculate PPS at right speed.... @@ -1797,7 +1893,8 @@ class ProxlwAFTRProfileHelper(ProxProfileHelper): 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, self.traffic_context(pkt_size, + self.pct_10gbps(value, line_speed)): with data_helper.measure_tot_stats(): time.sleep(duration) # Getting statistics to calculate PPS at right speed.... diff --git a/yardstick/network_services/vnf_generic/vnf/prox_vnf.py b/yardstick/network_services/vnf_generic/vnf/prox_vnf.py index 285e08659..839f30967 100644 --- a/yardstick/network_services/vnf_generic/vnf/prox_vnf.py +++ b/yardstick/network_services/vnf_generic/vnf/prox_vnf.py @@ -15,14 +15,13 @@ import errno import logging import datetime -import time - 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 import constants +from yardstick.benchmark.contexts import base as context_base LOG = logging.getLogger(__name__) @@ -35,7 +34,8 @@ class ProxApproxVnf(SampleVNF): VNF_PROMPT = "PROX started" LUA_PARAMETER_NAME = "sut" - def __init__(self, name, vnfd, setup_env_helper_type=None, resource_helper_type=None): + def __init__(self, name, vnfd, task_id, setup_env_helper_type=None, + resource_helper_type=None): if setup_env_helper_type is None: setup_env_helper_type = ProxDpdkVnfSetupEnvHelper @@ -44,9 +44,10 @@ class ProxApproxVnf(SampleVNF): self.prev_packets_in = 0 self.prev_packets_sent = 0 - self.prev_time = time.time() - super(ProxApproxVnf, self).__init__(name, vnfd, setup_env_helper_type, - resource_helper_type) + self.prev_tsc = 0 + self.tsc_hz = 0 + super(ProxApproxVnf, self).__init__( + name, vnfd, task_id, setup_env_helper_type, resource_helper_type) def _vnf_up_post(self): self.resource_helper.up_post() @@ -68,50 +69,75 @@ class ProxApproxVnf(SampleVNF): def collect_kpi(self): # we can't get KPIs if the VNF is down - check_if_process_failed(self._vnf_process) + check_if_process_failed(self._vnf_process, 0.01) + + physical_node = context_base.Context.get_physical_node_from_server( + self.scenario_helper.nodes[self.name]) + + result = {"physical_node": physical_node} if self.resource_helper is None: - result = { + result.update({ "packets_in": 0, "packets_dropped": 0, "packets_fwd": 0, "collect_stats": {"core": {}}, - } + }) return result + if (self.tsc_hz == 0): + self.tsc_hz = float(self.resource_helper.sut.hz()) + LOG.debug("TSC = %f", self.tsc_hz) + if (self.tsc_hz == 0): + raise RuntimeError("Unable to retrieve TSC") + # use all_ports so we only use ports matched in topology port_count = len(self.vnfd_helper.port_pairs.all_ports) if port_count not in {1, 2, 4}: raise RuntimeError("Failed ..Invalid no of ports .. " "1, 2 or 4 ports only supported at this time") - self.port_stats = self.vnf_execute('port_stats', range(port_count)) - curr_time = time.time() + all_port_stats = self.vnf_execute('multi_port_stats', range(port_count)) + rx_total = tx_total = tsc = 0 try: - rx_total = self.port_stats[6] - tx_total = self.port_stats[7] - except IndexError: - LOG.debug("port_stats parse fail ") - # return empty dict so we don't mess up existing KPIs + for single_port_stats in all_port_stats: + rx_total = rx_total + single_port_stats[1] + tx_total = tx_total + single_port_stats[2] + tsc = tsc + single_port_stats[5] + except (TypeError, IndexError): + LOG.error("Invalid data ...") return {} - result = { + tsc = tsc / port_count + + result.update({ "packets_in": rx_total, "packets_dropped": max((tx_total - rx_total), 0), "packets_fwd": tx_total, # we share ProxResourceHelper with TG, but we want to collect # collectd KPIs here and not TG KPIs, so use a different method name "collect_stats": self.resource_helper.collect_collectd_kpi(), - } - curr_packets_in = int((rx_total - self.prev_packets_in) / (curr_time - self.prev_time)) - curr_packets_fwd = int((tx_total - self.prev_packets_sent) / (curr_time - self.prev_time)) + }) + try: + curr_packets_in = int(((rx_total - self.prev_packets_in) * self.tsc_hz) + / (tsc - self.prev_tsc)) + except ZeroDivisionError: + LOG.error("Error.... Divide by Zero") + curr_packets_in = 0 + + try: + curr_packets_fwd = int(((tx_total - self.prev_packets_sent) * self.tsc_hz) + / (tsc - self.prev_tsc)) + except ZeroDivisionError: + LOG.error("Error.... Divide by Zero") + curr_packets_fwd = 0 result["curr_packets_in"] = curr_packets_in result["curr_packets_fwd"] = curr_packets_fwd self.prev_packets_in = rx_total self.prev_packets_sent = tx_total - self.prev_time = curr_time + self.prev_tsc = tsc LOG.debug("%s collect KPIs %s %s", self.APP_NAME, datetime.datetime.now(), result) return result diff --git a/yardstick/network_services/vnf_generic/vnf/router_vnf.py b/yardstick/network_services/vnf_generic/vnf/router_vnf.py index aea27ffa6..e99de9cb3 100644 --- a/yardstick/network_services/vnf_generic/vnf/router_vnf.py +++ b/yardstick/network_services/vnf_generic/vnf/router_vnf.py @@ -34,7 +34,8 @@ class RouterVNF(SampleVNF): WAIT_TIME = 1 - def __init__(self, name, vnfd, setup_env_helper_type=None, resource_helper_type=None): + def __init__(self, name, vnfd, task_id, setup_env_helper_type=None, + resource_helper_type=None): if setup_env_helper_type is None: setup_env_helper_type = DpdkVnfSetupEnvHelper @@ -42,12 +43,12 @@ class RouterVNF(SampleVNF): vnfd['mgmt-interface'].pop("pkey", "") vnfd['mgmt-interface']['password'] = 'password' - super(RouterVNF, self).__init__(name, vnfd, setup_env_helper_type, resource_helper_type) + super(RouterVNF, self).__init__( + name, vnfd, task_id, setup_env_helper_type, resource_helper_type) def instantiate(self, scenario_cfg, context_cfg): self.scenario_helper.scenario_cfg = scenario_cfg self.context_cfg = context_cfg - self.nfvi_context = Context.get_context_from_server(self.scenario_helper.nodes[self.name]) self.configure_routes(self.name, scenario_cfg, context_cfg) def wait_for_instantiate(self): @@ -107,8 +108,11 @@ class RouterVNF(SampleVNF): stdout = self.ssh_helper.execute(ip_link_stats)[1] link_stats = self.get_stats(stdout) # get RX/TX from link_stats and assign to results + physical_node = Context.get_physical_node_from_server( + self.scenario_helper.nodes[self.name]) result = { + "physical_node": physical_node, "packets_in": 0, "packets_dropped": 0, "packets_fwd": 0, diff --git a/yardstick/network_services/vnf_generic/vnf/sample_vnf.py b/yardstick/network_services/vnf_generic/vnf/sample_vnf.py index 34b0260b4..3ef7c33c5 100644 --- a/yardstick/network_services/vnf_generic/vnf/sample_vnf.py +++ b/yardstick/network_services/vnf_generic/vnf/sample_vnf.py @@ -11,15 +11,13 @@ # 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. -""" Base class implementation for generic vnf implementation """ -from collections import Mapping import logging from multiprocessing import Queue, Value, Process - import os import posixpath import re +import uuid import subprocess import time @@ -32,6 +30,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.common import yaml_loader 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 @@ -41,7 +40,7 @@ from yardstick.network_services.vnf_generic.vnf.base import GenericTrafficGen from yardstick.network_services.vnf_generic.vnf.base import GenericVNF from yardstick.network_services.vnf_generic.vnf.base import QueueFileWrapper from yardstick.network_services.vnf_generic.vnf.vnf_ssh_helper import VnfSshHelper - +from yardstick.benchmark.contexts.node import NodeContext LOG = logging.getLogger(__name__) @@ -144,6 +143,13 @@ class DpdkVnfSetupEnvHelper(SetupEnvHelper): 'vnf_type': self.VNF_TYPE, } + # read actions/rules from file + acl_options = None + acl_file_name = self.scenario_helper.options.get('rules') + if acl_file_name: + with utils.open_relative_file(acl_file_name, task_path) as infile: + acl_options = yaml_loader.yaml_load(infile) + config_tpl_cfg = utils.find_relative_file(self.DEFAULT_CONFIG_TPL_CFG, task_path) config_basename = posixpath.basename(self.CFG_CONFIG) @@ -176,12 +182,17 @@ class DpdkVnfSetupEnvHelper(SetupEnvHelper): new_config = self._update_packet_type(new_config, traffic_options) self.ssh_helper.upload_config_file(config_basename, new_config) self.ssh_helper.upload_config_file(script_basename, - multiport.generate_script(self.vnfd_helper)) + multiport.generate_script(self.vnfd_helper, + self.get_flows_config(acl_options))) LOG.info("Provision and start the %s", self.APP_NAME) self._build_pipeline_kwargs() return self.PIPELINE_COMMAND.format(**self.pipeline_kwargs) + def get_flows_config(self, options=None): # pylint: disable=unused-argument + """No actions/rules (flows) by default""" + return None + def _build_pipeline_kwargs(self): tool_path = self.ssh_helper.provision_tool(tool_file=self.APP_NAME) # count the number of actual ports in the list of pairs @@ -193,11 +204,20 @@ class DpdkVnfSetupEnvHelper(SetupEnvHelper): port_nums = self.vnfd_helper.port_nums(ports) # create mask from all the dpdk port numbers ports_mask_hex = hex(sum(2 ** num for num in port_nums)) + + vnf_cfg = self.scenario_helper.vnf_cfg + lb_config = vnf_cfg.get('lb_config', 'SW') + worker_threads = vnf_cfg.get('worker_threads', 3) + hwlb = '' + if lb_config == 'HW': + hwlb = ' --hwlb %s' % worker_threads + self.pipeline_kwargs = { 'cfg_file': self.CFG_CONFIG, 'script': self.CFG_SCRIPT, 'port_mask_hex': ports_mask_hex, 'tool_path': tool_path, + 'hwlb': hwlb, } def setup_vnf_environment(self): @@ -300,6 +320,7 @@ class ResourceHelper(object): self.resource = None self.setup_helper = setup_helper self.ssh_helper = setup_helper.ssh_helper + self._enable = True def setup(self): self.resource = self.setup_helper.setup_vnf_environment() @@ -307,22 +328,33 @@ class ResourceHelper(object): def generate_cfg(self): pass + def update_from_context(self, context, attr_name): + """Disable resource helper in case of baremetal context. + + And update appropriate node collectd options in context + """ + if isinstance(context, NodeContext): + self._enable = False + context.update_collectd_options_for_node(self.setup_helper.collectd_options, + attr_name) + def _collect_resource_kpi(self): result = {} status = self.resource.check_if_system_agent_running("collectd")[0] - if status == 0: + if status == 0 and self._enable: result = self.resource.amqp_collect_nfvi_kpi() result = {"core": result} return result def start_collect(self): - self.resource.initiate_systemagent(self.ssh_helper.bin_path) - self.resource.start() - self.resource.amqp_process_for_nfvi_kpi() + if self._enable: + self.resource.initiate_systemagent(self.ssh_helper.bin_path) + self.resource.start() + self.resource.amqp_process_for_nfvi_kpi() def stop_collect(self): - if self.resource: + if self.resource and self._enable: self.resource.stop() def collect_kpi(self): @@ -366,48 +398,24 @@ class ClientResourceHelper(ResourceHelper): LOG.error('TRex client not connected') return {} - def generate_samples(self, ports, key=None, default=None): - # needs to be used ports - last_result = self.get_stats(ports) - key_value = last_result.get(key, default) - - if not isinstance(last_result, Mapping): # added for mock unit test - self._terminated.value = 1 - return {} - - samples = {} - # recalculate port for interface and see if it matches ports provided - for intf in self.vnfd_helper.interfaces: - name = intf["name"] - port = self.vnfd_helper.port_num(name) - if port in ports: - xe_value = last_result.get(port, {}) - samples[name] = { - "rx_throughput_fps": float(xe_value.get("rx_pps", 0.0)), - "tx_throughput_fps": float(xe_value.get("tx_pps", 0.0)), - "rx_throughput_mbps": float(xe_value.get("rx_bps", 0.0)), - "tx_throughput_mbps": float(xe_value.get("tx_bps", 0.0)), - "in_packets": int(xe_value.get("ipackets", 0)), - "out_packets": int(xe_value.get("opackets", 0)), - } - if key: - samples[name][key] = key_value - return samples + def _get_samples(self, ports, port_pg_id=False): + raise NotImplementedError() def _run_traffic_once(self, traffic_profile): traffic_profile.execute_traffic(self) self.client_started.value = 1 time.sleep(self.RUN_DURATION) - samples = self.generate_samples(traffic_profile.ports) + samples = self._get_samples(traffic_profile.ports) time.sleep(self.QUEUE_WAIT_TIME) self._queue.put(samples) - def run_traffic(self, traffic_profile): + def run_traffic(self, traffic_profile, mq_producer): # if we don't do this we can hang waiting for the queue to drain # have to do this in the subprocess self._queue.cancel_join_thread() # fixme: fix passing correct trex config file, # instead of searching the default path + mq_producer.tg_method_started() try: self._build_ports() self.client = self._connect() @@ -415,8 +423,11 @@ class ClientResourceHelper(ResourceHelper): self.client.remove_all_streams(self.all_ports) # remove all streams traffic_profile.register_generator(self) + iteration_index = 0 while self._terminated.value == 0: + iteration_index += 1 self._run_traffic_once(traffic_profile) + mq_producer.tg_method_iteration(iteration_index) self.client.stop(self.all_ports) self.client.disconnect() @@ -427,6 +438,8 @@ class ClientResourceHelper(ResourceHelper): return # return if trex/tg server is stopped. raise + mq_producer.tg_method_finished() + def terminate(self): self._terminated.value = 1 # stop client @@ -606,6 +619,7 @@ class ScenarioHelper(object): 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 """ @@ -615,8 +629,9 @@ class SampleVNF(GenericVNF): APP_NAME = "SampleVNF" # we run the VNF interactively, so the ssh command will timeout after this long - def __init__(self, name, vnfd, setup_env_helper_type=None, resource_helper_type=None): - super(SampleVNF, self).__init__(name, vnfd) + def __init__(self, name, vnfd, task_id, setup_env_helper_type=None, + resource_helper_type=None): + super(SampleVNF, self).__init__(name, vnfd, task_id) self.bin_path = get_nsb_option('bin_path', '') self.scenario_helper = ScenarioHelper(self.name) @@ -637,7 +652,6 @@ class SampleVNF(GenericVNF): self.resource_helper = resource_helper_type(self.setup_helper) self.context_cfg = None - self.nfvi_context = None self.pipeline_kwargs = {} self.uplink_ports = None self.downlink_ports = None @@ -664,8 +678,10 @@ class SampleVNF(GenericVNF): self._update_collectd_options(scenario_cfg, context_cfg) self.scenario_helper.scenario_cfg = scenario_cfg self.context_cfg = context_cfg - self.nfvi_context = Context.get_context_from_server(self.scenario_helper.nodes[self.name]) - # self.nfvi_context = None + self.resource_helper.update_from_context( + Context.get_context_from_server(self.scenario_helper.nodes[self.name]), + self.scenario_helper.nodes[self.name] + ) # vnf deploy is unsupported, use ansible playbooks if self.scenario_helper.options.get("vnf_deploy", False): @@ -816,18 +832,21 @@ class SampleVNF(GenericVNF): def collect_kpi(self): # we can't get KPIs if the VNF is down - check_if_process_failed(self._vnf_process) + check_if_process_failed(self._vnf_process, 0.01) stats = self.get_stats() m = re.search(self.COLLECT_KPI, stats, re.MULTILINE) + physical_node = Context.get_physical_node_from_server( + self.scenario_helper.nodes[self.name]) + + result = {"physical_node": physical_node} if m: - result = {k: int(m.group(v)) for k, v in self.COLLECT_MAP.items()} + result.update({k: int(m.group(v)) for k, v in self.COLLECT_MAP.items()}) result["collect_stats"] = self.resource_helper.collect_kpi() else: - result = { - "packets_in": 0, - "packets_fwd": 0, - "packets_dropped": 0, - } + result.update({"packets_in": 0, + "packets_fwd": 0, + "packets_dropped": 0}) + LOG.debug("%s collect KPIs %s", self.APP_NAME, result) return result @@ -843,8 +862,9 @@ class SampleVNFTrafficGen(GenericTrafficGen): APP_NAME = 'Sample' RUN_WAIT = 1 - def __init__(self, name, vnfd, setup_env_helper_type=None, resource_helper_type=None): - super(SampleVNFTrafficGen, self).__init__(name, vnfd) + def __init__(self, name, vnfd, task_id, setup_env_helper_type=None, + resource_helper_type=None): + super(SampleVNFTrafficGen, self).__init__(name, vnfd, task_id) self.bin_path = get_nsb_option('bin_path', '') self.scenario_helper = ScenarioHelper(self.name) @@ -873,6 +893,11 @@ class SampleVNFTrafficGen(GenericTrafficGen): def instantiate(self, scenario_cfg, context_cfg): self.scenario_helper.scenario_cfg = scenario_cfg + self.resource_helper.update_from_context( + Context.get_context_from_server(self.scenario_helper.nodes[self.name]), + self.scenario_helper.nodes[self.name] + ) + self.resource_helper.setup() # must generate_cfg after DPDK bind because we need port number self.resource_helper.generate_cfg() @@ -896,12 +921,13 @@ class SampleVNFTrafficGen(GenericTrafficGen): LOG.info("%s TG Server is up and running.", self.APP_NAME) return self._tg_process.exitcode - def _traffic_runner(self, traffic_profile): + def _traffic_runner(self, traffic_profile, mq_id): # always drop connections first thing in new processes # so we don't get paramiko errors self.ssh_helper.drop_connection() LOG.info("Starting %s client...", self.APP_NAME) - self.resource_helper.run_traffic(traffic_profile) + self._mq_producer = self._setup_mq_producer(mq_id) + self.resource_helper.run_traffic(traffic_profile, self._mq_producer) def run_traffic(self, traffic_profile): """ Generate traffic on the wire according to the given params. @@ -911,10 +937,12 @@ class SampleVNFTrafficGen(GenericTrafficGen): :param traffic_profile: :return: True/False """ - name = "{}-{}-{}-{}".format(self.name, self.APP_NAME, traffic_profile.__class__.__name__, + name = '{}-{}-{}-{}'.format(self.name, self.APP_NAME, + traffic_profile.__class__.__name__, os.getpid()) - self._traffic_process = Process(name=name, target=self._traffic_runner, - args=(traffic_profile,)) + self._traffic_process = Process( + name=name, target=self._traffic_runner, + args=(traffic_profile, uuid.uuid1().int)) self._traffic_process.start() # Wait for traffic process to start while self.resource_helper.client_started.value == 0: @@ -923,13 +951,16 @@ class SampleVNFTrafficGen(GenericTrafficGen): if not self._traffic_process.is_alive(): break - return self._traffic_process.is_alive() - def collect_kpi(self): # check if the tg processes have exited + physical_node = Context.get_physical_node_from_server( + self.scenario_helper.nodes[self.name]) + + result = {"physical_node": physical_node} for proc in (self._tg_process, self._traffic_process): check_if_process_failed(proc) - result = self.resource_helper.collect_kpi() + + result["collect_stats"] = self.resource_helper.collect_kpi() LOG.debug("%s collect KPIs %s", self.APP_NAME, result) return result diff --git a/yardstick/network_services/vnf_generic/vnf/tg_ixload.py b/yardstick/network_services/vnf_generic/vnf/tg_ixload.py index 02e7803f7..e0fc47dbf 100644 --- a/yardstick/network_services/vnf_generic/vnf/tg_ixload.py +++ b/yardstick/network_services/vnf_generic/vnf/tg_ixload.py @@ -12,15 +12,13 @@ # See the License for the specific language governing permissions and # limitations under the License. -from __future__ import absolute_import +import collections import csv import glob import logging import os import shutil - -from collections import OrderedDict -from subprocess import call +import subprocess from yardstick.common import utils from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNFTrafficGen @@ -65,7 +63,7 @@ class IxLoadResourceHelper(ClientResourceHelper): RESULTS_MOUNT = "/mnt/Results" - KPI_LIST = OrderedDict(( + KPI_LIST = collections.OrderedDict(( ('http_throughput', 'HTTP Total Throughput (Kbps)'), ('simulated_users', 'HTTP Simulated Users'), ('concurrent_connections', 'HTTP Concurrent Connections'), @@ -75,7 +73,8 @@ class IxLoadResourceHelper(ClientResourceHelper): def __init__(self, setup_helper): super(IxLoadResourceHelper, self).__init__(setup_helper) - self.result = OrderedDict((key, ResourceDataHelper()) for key in self.KPI_LIST) + self.result = collections.OrderedDict((key, ResourceDataHelper()) + for key in self.KPI_LIST) self.resource_file_name = '' self.data = None @@ -101,7 +100,7 @@ class IxLoadResourceHelper(ClientResourceHelper): LOG.debug(cmd) if not os.path.ismount(self.RESULTS_MOUNT): - call(cmd, shell=True) + subprocess.call(cmd, shell=True) shutil.rmtree(self.RESULTS_MOUNT, ignore_errors=True) utils.makedirs(self.RESULTS_MOUNT) @@ -124,12 +123,13 @@ class IxLoadResourceHelper(ClientResourceHelper): class IxLoadTrafficGen(SampleVNFTrafficGen): - def __init__(self, name, vnfd, setup_env_helper_type=None, resource_helper_type=None): + def __init__(self, name, vnfd, task_id, setup_env_helper_type=None, + resource_helper_type=None): if resource_helper_type is None: resource_helper_type = IxLoadResourceHelper - super(IxLoadTrafficGen, self).__init__(name, vnfd, setup_env_helper_type, - resource_helper_type) + super(IxLoadTrafficGen, self).__init__( + name, vnfd, task_id, setup_env_helper_type, resource_helper_type) self._result = {} def run_traffic(self, traffic_profile): @@ -157,7 +157,7 @@ class IxLoadTrafficGen(SampleVNFTrafficGen): args="'%s'" % ixload_config) LOG.debug(cmd) - call(cmd, shell=True) + subprocess.call(cmd, shell=True) with open(self.ssh_helper.join_bin_path("ixLoad_HTTP_Client.csv")) as csv_file: lines = csv_file.readlines()[10:] @@ -172,5 +172,5 @@ class IxLoadTrafficGen(SampleVNFTrafficGen): self.resource_helper.data = self.resource_helper.make_aggregates() def terminate(self): - call(["pkill", "-9", "http_ixload.py"]) + subprocess.call(["pkill", "-9", "http_ixload.py"]) super(IxLoadTrafficGen, self).terminate() diff --git a/yardstick/network_services/vnf_generic/vnf/tg_ping.py b/yardstick/network_services/vnf_generic/vnf/tg_ping.py index a989543f5..a3b5afa39 100644 --- a/yardstick/network_services/vnf_generic/vnf/tg_ping.py +++ b/yardstick/network_services/vnf_generic/vnf/tg_ping.py @@ -71,7 +71,7 @@ class PingResourceHelper(ClientResourceHelper): self._queue = Queue() self._parser = PingParser(self._queue) - def run_traffic(self, traffic_profile): + def run_traffic(self, traffic_profile, *args): # drop the connection in order to force a new one self.ssh_helper.drop_connection() @@ -103,14 +103,14 @@ class PingTrafficGen(SampleVNFTrafficGen): APP_NAME = 'Ping' RUN_WAIT = 4 - def __init__(self, name, vnfd, setup_env_helper_type=None, resource_helper_type=None): + def __init__(self, name, vnfd, task_id, setup_env_helper_type=None, + resource_helper_type=None): if setup_env_helper_type is None: setup_env_helper_type = PingSetupEnvHelper if resource_helper_type is None: resource_helper_type = PingResourceHelper - - super(PingTrafficGen, self).__init__(name, vnfd, setup_env_helper_type, - resource_helper_type) + super(PingTrafficGen, self).__init__( + name, vnfd, task_id, setup_env_helper_type, resource_helper_type) self._result = {} def _check_status(self): diff --git a/yardstick/network_services/vnf_generic/vnf/tg_pktgen.py b/yardstick/network_services/vnf_generic/vnf/tg_pktgen.py new file mode 100644 index 000000000..9d452213f --- /dev/null +++ b/yardstick/network_services/vnf_generic/vnf/tg_pktgen.py @@ -0,0 +1,103 @@ +# Copyright (c) 2018 Intel Corporation +# +# 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. + +import logging +import multiprocessing +import time +import uuid + +from yardstick.common import constants +from yardstick.common import exceptions +from yardstick.common import utils +from yardstick.network_services.vnf_generic.vnf import base as vnf_base + + +LOG = logging.getLogger(__name__) + + +class PktgenTrafficGen(vnf_base.GenericTrafficGen, + vnf_base.GenericVNFEndpoint): + """DPDK Pktgen traffic generator + + Website: http://pktgen-dpdk.readthedocs.io/en/latest/index.html + """ + + TIMEOUT = 30 + + def __init__(self, name, vnfd, task_id): + vnf_base.GenericTrafficGen.__init__(self, name, vnfd, task_id) + self.queue = multiprocessing.Queue() + self._id = uuid.uuid1().int + self._mq_producer = self._setup_mq_producer(self._id) + vnf_base.GenericVNFEndpoint.__init__(self, self._id, [task_id], + self.queue) + self._consumer = vnf_base.GenericVNFConsumer([task_id], self) + self._consumer.start_rpc_server() + self._traffic_profile = None + self._node_ip = vnfd['mgmt-interface'].get('ip') + self._lua_node_port = self._get_lua_node_port( + vnfd['mgmt-interface'].get('service_ports', [])) + self._rate = 1 + + def instantiate(self, scenario_cfg, context_cfg): # pragma: no cover + pass + + def run_traffic(self, traffic_profile): + self._traffic_profile = traffic_profile + self._traffic_profile.init(self._node_ip, self._lua_node_port) + utils.wait_until_true(self._is_running, timeout=self.TIMEOUT, + sleep=2) + + def terminate(self): # pragma: no cover + pass + + def collect_kpi(self): # pragma: no cover + pass + + def scale(self, flavor=''): # pragma: no cover + pass + + def wait_for_instantiate(self): # pragma: no cover + pass + + def runner_method_start_iteration(self, ctxt, **kwargs): + # pragma: no cover + LOG.debug('Start method') + # NOTE(ralonsoh): 'rate' should be modified between iterations. The + # current implementation is just for testing. + self._rate += 1 + self._traffic_profile.start() + self._traffic_profile.rate(self._rate) + time.sleep(4) + self._traffic_profile.stop() + self._mq_producer.tg_method_iteration(1, 1, {}) + + def runner_method_stop_iteration(self, ctxt, **kwargs): # pragma: no cover + # pragma: no cover + LOG.debug('Stop method') + + @staticmethod + def _get_lua_node_port(service_ports): + for port in (port for port in service_ports if + int(port['port']) == constants.LUA_PORT): + return int(port['node_port']) + # NOTE(ralonsoh): in case LUA port is not present, an exception should + # be raised. + + def _is_running(self): + try: + self._traffic_profile.help() + return True + except exceptions.PktgenActionError: + return False diff --git a/yardstick/network_services/vnf_generic/vnf/tg_prox.py b/yardstick/network_services/vnf_generic/vnf/tg_prox.py index 282dd92c5..854319a21 100644 --- a/yardstick/network_services/vnf_generic/vnf/tg_prox.py +++ b/yardstick/network_services/vnf_generic/vnf/tg_prox.py @@ -30,9 +30,11 @@ class ProxTrafficGen(SampleVNFTrafficGen): LUA_PARAMETER_NAME = "gen" WAIT_TIME = 1 - def __init__(self, name, vnfd, setup_env_helper_type=None, resource_helper_type=None): + def __init__(self, name, vnfd, task_id, setup_env_helper_type=None, + resource_helper_type=None): # don't call superclass, use custom wrapper of ProxApproxVnf - self._vnf_wrapper = ProxApproxVnf(name, vnfd, setup_env_helper_type, resource_helper_type) + self._vnf_wrapper = ProxApproxVnf( + name, vnfd, task_id, setup_env_helper_type, resource_helper_type) self.bin_path = get_nsb_option('bin_path', '') self.name = self._vnf_wrapper.name self.ssh_helper = self._vnf_wrapper.ssh_helper diff --git a/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_ixia.py b/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_ixia.py index 265d0b7a9..4d3bc2ce5 100644 --- a/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_ixia.py +++ b/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_ixia.py @@ -12,31 +12,19 @@ # See the License for the specific language governing permissions and # limitations under the License. -from __future__ import absolute_import - -import time -import os import logging -import sys from yardstick.common import utils -from yardstick import error +from yardstick.network_services.libs.ixia_libs.ixnet import ixnet_api from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNFTrafficGen from yardstick.network_services.vnf_generic.vnf.sample_vnf import ClientResourceHelper from yardstick.network_services.vnf_generic.vnf.sample_vnf import Rfc2544ResourceHelper + LOG = logging.getLogger(__name__) WAIT_AFTER_CFG_LOAD = 10 WAIT_FOR_TRAFFIC = 30 -IXIA_LIB = os.path.dirname(os.path.realpath(__file__)) -IXNET_LIB = os.path.join(IXIA_LIB, "../../libs/ixia_libs/IxNet") -sys.path.append(IXNET_LIB) - -try: - from IxNet import IxNextgen -except ImportError: - IxNextgen = error.ErrorClass class IxiaRfc2544Helper(Rfc2544ResourceHelper): @@ -53,7 +41,7 @@ class IxiaResourceHelper(ClientResourceHelper): super(IxiaResourceHelper, self).__init__(setup_helper) self.scenario_helper = setup_helper.scenario_helper - self.client = IxNextgen() + self.client = ixnet_api.IxNextgen() if rfc_helper_type is None: rfc_helper_type = IxiaRfc2544Helper @@ -64,20 +52,16 @@ class IxiaResourceHelper(ClientResourceHelper): self._connect() def _connect(self, client=None): - self.client._connect(self.vnfd_helper) + self.client.connect(self.vnfd_helper) def get_stats(self, *args, **kwargs): - return self.client.ix_get_statistics() + return self.client.get_statistics() def stop_collect(self): self._terminated.value = 1 - if self.client: - self.client.ix_stop_traffic() - def generate_samples(self, ports, key=None, default=None): + def generate_samples(self, ports, key=None): stats = self.get_stats() - last_result = stats[1] - latency = stats[0] samples = {} # this is not DPDK port num, but this is whatever number we gave @@ -88,19 +72,21 @@ class IxiaResourceHelper(ClientResourceHelper): intf = self.vnfd_helper.find_interface_by_port(port_num) port_name = intf["name"] samples[port_name] = { - "rx_throughput_kps": float(last_result["Rx_Rate_Kbps"][port_num]), - "tx_throughput_kps": float(last_result["Tx_Rate_Kbps"][port_num]), - "rx_throughput_mbps": float(last_result["Rx_Rate_Mbps"][port_num]), - "tx_throughput_mbps": float(last_result["Tx_Rate_Mbps"][port_num]), - "in_packets": int(last_result["Valid_Frames_Rx"][port_num]), - "out_packets": int(last_result["Frames_Tx"][port_num]), - "RxThroughput": int(last_result["Valid_Frames_Rx"][port_num]) / 30, - "TxThroughput": int(last_result["Frames_Tx"][port_num]) / 30, + "rx_throughput_kps": float(stats["Rx_Rate_Kbps"][port_num]), + "tx_throughput_kps": float(stats["Tx_Rate_Kbps"][port_num]), + "rx_throughput_mbps": float(stats["Rx_Rate_Mbps"][port_num]), + "tx_throughput_mbps": float(stats["Tx_Rate_Mbps"][port_num]), + "in_packets": int(stats["Valid_Frames_Rx"][port_num]), + "out_packets": int(stats["Frames_Tx"][port_num]), + # NOTE(ralonsoh): we need to make the traffic injection + # time variable. + "RxThroughput": int(stats["Valid_Frames_Rx"][port_num]) / 30, + "TxThroughput": int(stats["Frames_Tx"][port_num]) / 30, } if key: - avg_latency = latency["Store-Forward_Avg_latency_ns"][port_num] - min_latency = latency["Store-Forward_Min_latency_ns"][port_num] - max_latency = latency["Store-Forward_Max_latency_ns"][port_num] + avg_latency = stats["Store-Forward_Avg_latency_ns"][port_num] + min_latency = stats["Store-Forward_Min_latency_ns"][port_num] + max_latency = stats["Store-Forward_Max_latency_ns"][port_num] samples[port_name][key] = \ {"Store-Forward_Avg_latency_ns": avg_latency, "Store-Forward_Min_latency_ns": min_latency, @@ -110,7 +96,13 @@ class IxiaResourceHelper(ClientResourceHelper): return samples - def run_traffic(self, traffic_profile): + def _initialize_client(self): + """Initialize the IXIA IxNetwork client and configure the server""" + self.client.clear_config() + self.client.assign_ports() + self.client.create_traffic_model() + + def run_traffic(self, traffic_profile, *args): if self._terminated.value: return @@ -119,16 +111,7 @@ class IxiaResourceHelper(ClientResourceHelper): default = "00:00:00:00:00:00" self._build_ports() - - # we don't know client_file_name until runtime as instantiate - client_file_name = \ - utils.find_relative_file( - self.scenario_helper.scenario_cfg['ixia_profile'], - self.scenario_helper.scenario_cfg["task_path"]) - self.client.ix_load_config(client_file_name) - time.sleep(WAIT_AFTER_CFG_LOAD) - - self.client.ix_assign_ports() + self._initialize_client() mac = {} for port_name in self.vnfd_helper.port_pairs.all_ports: @@ -140,43 +123,28 @@ class IxiaResourceHelper(ClientResourceHelper): mac["src_mac_{}".format(port_num)] = virt_intf.get("local_mac", default) mac["dst_mac_{}".format(port_num)] = virt_intf.get("dst_mac", default) - samples = {} - # Generate ixia traffic config... try: while not self._terminated.value: - traffic_profile.execute_traffic(self, self.client, mac) + first_run = traffic_profile.execute_traffic( + self, self.client, mac) self.client_started.value = 1 - time.sleep(WAIT_FOR_TRAFFIC) - self.client.ix_stop_traffic() + # pylint: disable=unnecessary-lambda + utils.wait_until_true(lambda: self.client.is_traffic_stopped()) samples = self.generate_samples(traffic_profile.ports) + + # NOTE(ralonsoh): the traffic injection duration is fixed to 30 + # seconds. This parameter is configurable and must be retrieved + # from the traffic_profile.full_profile information. + # Every flow must have the same duration. + completed, samples = traffic_profile.get_drop_percentage( + samples, min_tol, max_tol, first_run=first_run) self._queue.put(samples) - status, samples = traffic_profile.get_drop_percentage(samples, min_tol, - max_tol, self.client, mac) - current = samples['CurrentDropPercentage'] - if min_tol <= current <= max_tol or status == 'Completed': + if completed: self._terminated.value = 1 - self.client.ix_stop_traffic() - self._queue.put(samples) - - if not self.rfc_helper.is_done(): - self._terminated.value = 1 - return - - traffic_profile.execute_traffic(self, self.client, mac) - for _ in range(5): - time.sleep(self.LATENCY_TIME_SLEEP) - self.client.ix_stop_traffic() - samples = self.generate_samples(traffic_profile.ports, 'latency', {}) - self._queue.put(samples) - traffic_profile.start_ixia_latency(self, self.client, mac) - if self._terminated.value: - break - - self.client.ix_stop_traffic() except Exception: # pylint: disable=broad-except - LOG.exception("Run Traffic terminated") + LOG.exception('Run Traffic terminated') self._terminated.value = 1 @@ -189,12 +157,12 @@ class IxiaTrafficGen(SampleVNFTrafficGen): APP_NAME = 'Ixia' - def __init__(self, name, vnfd, setup_env_helper_type=None, resource_helper_type=None): + def __init__(self, name, vnfd, task_id, setup_env_helper_type=None, + resource_helper_type=None): if resource_helper_type is None: resource_helper_type = IxiaResourceHelper - - super(IxiaTrafficGen, self).__init__(name, vnfd, setup_env_helper_type, - resource_helper_type) + super(IxiaTrafficGen, self).__init__( + name, vnfd, task_id, setup_env_helper_type, resource_helper_type) self._ixia_traffic_gen = None self.ixia_file_name = '' self.vnf_port_pairs = [] diff --git a/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_trex.py b/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_trex.py index 4e9f4bdc1..cdbb41485 100644 --- a/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_trex.py +++ b/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_trex.py @@ -11,74 +11,45 @@ # 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. -""" Trex traffic generation definitions which implements rfc2544 """ -from __future__ import absolute_import -from __future__ import print_function -import time import logging -from collections import Mapping - -from yardstick.network_services.vnf_generic.vnf.tg_trex import TrexTrafficGen -from yardstick.network_services.vnf_generic.vnf.sample_vnf import Rfc2544ResourceHelper -from yardstick.network_services.vnf_generic.vnf.tg_trex import TrexResourceHelper - -LOGGING = logging.getLogger(__name__) +import time +from yardstick.common import utils +from yardstick.network_services.vnf_generic.vnf import sample_vnf +from yardstick.network_services.vnf_generic.vnf import tg_trex -class TrexRfc2544ResourceHelper(Rfc2544ResourceHelper): - def is_done(self): - return self.latency and self.iteration.value > 10 +LOGGING = logging.getLogger(__name__) -class TrexRfcResourceHelper(TrexResourceHelper): +class TrexRfcResourceHelper(tg_trex.TrexResourceHelper): - LATENCY_TIME_SLEEP = 120 - RUN_DURATION = 30 - WAIT_TIME = 3 + SAMPLING_PERIOD = 2 + TRANSIENT_PERIOD = 10 - def __init__(self, setup_helper, rfc_helper_type=None): + def __init__(self, setup_helper): super(TrexRfcResourceHelper, self).__init__(setup_helper) - - if rfc_helper_type is None: - rfc_helper_type = TrexRfc2544ResourceHelper - - self.rfc2544_helper = rfc_helper_type(self.scenario_helper) + self.rfc2544_helper = sample_vnf.Rfc2544ResourceHelper( + self.scenario_helper) def _run_traffic_once(self, traffic_profile): - if self._terminated.value: - return - - traffic_profile.execute_traffic(self) self.client_started.value = 1 - time.sleep(self.RUN_DURATION) - self.client.stop(traffic_profile.ports) - time.sleep(self.WAIT_TIME) - samples = traffic_profile.get_drop_percentage(self) - self._queue.put(samples) - - if not self.rfc2544_helper.is_done(): - return - - self.client.stop(traffic_profile.ports) - self.client.reset(ports=traffic_profile.ports) - self.client.remove_all_streams(traffic_profile.ports) - traffic_profile.execute_traffic_latency(samples=samples) - multiplier = traffic_profile.calculate_pps(samples)[1] - for _ in range(5): - time.sleep(self.LATENCY_TIME_SLEEP) - self.client.stop(traffic_profile.ports) - time.sleep(self.WAIT_TIME) - last_res = self.client.get_stats(traffic_profile.ports) - if not isinstance(last_res, Mapping): - self._terminated.value = 1 - continue - self.generate_samples(traffic_profile.ports, 'latency', {}) - self._queue.put(samples) - self.client.start(mult=str(multiplier), - ports=traffic_profile.ports, - duration=120, force=True) + ports, port_pg_id = traffic_profile.execute_traffic(self) + + samples = [] + timeout = int(traffic_profile.config.duration) - self.TRANSIENT_PERIOD + time.sleep(self.TRANSIENT_PERIOD) + for _ in utils.Timer(timeout=timeout): + samples.append(self._get_samples(ports, port_pg_id=port_pg_id)) + time.sleep(self.SAMPLING_PERIOD) + + traffic_profile.stop_traffic(self) + output = traffic_profile.get_drop_percentage( + samples, self.rfc2544_helper.tolerance_low, + self.rfc2544_helper.tolerance_high, + self.rfc2544_helper.correlated_traffic) + self._queue.put(output) def start_client(self, ports, mult=None, duration=None, force=True): self.client.start(ports=ports, mult=mult, duration=duration, force=force) @@ -86,20 +57,16 @@ class TrexRfcResourceHelper(TrexResourceHelper): def clear_client_stats(self, ports): self.client.clear_stats(ports=ports) - def collect_kpi(self): - self.rfc2544_helper.iteration.value += 1 - return super(TrexRfcResourceHelper, self).collect_kpi() - -class TrexTrafficGenRFC(TrexTrafficGen): +class TrexTrafficGenRFC(tg_trex.TrexTrafficGen): """ This class handles mapping traffic profile and generating traffic for rfc2544 testcase. """ - def __init__(self, name, vnfd, setup_env_helper_type=None, resource_helper_type=None): + def __init__(self, name, vnfd, task_id, setup_env_helper_type=None, + resource_helper_type=None): if resource_helper_type is None: resource_helper_type = TrexRfcResourceHelper - - super(TrexTrafficGenRFC, self).__init__(name, vnfd, setup_env_helper_type, - resource_helper_type) + super(TrexTrafficGenRFC, self).__init__( + name, vnfd, task_id, setup_env_helper_type, resource_helper_type) diff --git a/yardstick/network_services/vnf_generic/vnf/tg_trex.py b/yardstick/network_services/vnf_generic/vnf/tg_trex.py index 0084a124c..58b73488b 100644 --- a/yardstick/network_services/vnf_generic/vnf/tg_trex.py +++ b/yardstick/network_services/vnf_generic/vnf/tg_trex.py @@ -13,7 +13,6 @@ # limitations under the License. """ Trex acts as traffic generation and vnf definitions based on IETS Spec """ -from __future__ import absolute_import import logging import os @@ -25,6 +24,7 @@ from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNFTraff from yardstick.network_services.vnf_generic.vnf.sample_vnf import ClientResourceHelper from yardstick.network_services.vnf_generic.vnf.sample_vnf import DpdkVnfSetupEnvHelper + LOG = logging.getLogger(__name__) @@ -165,6 +165,30 @@ class TrexResourceHelper(ClientResourceHelper): cmd = "sudo fuser -n tcp %s %s -k > /dev/null 2>&1" self.ssh_helper.execute(cmd % (self.SYNC_PORT, self.ASYNC_PORT)) + def _get_samples(self, ports, port_pg_id=None): + stats = self.get_stats(ports) + samples = {} + for pname in (intf['name'] for intf in self.vnfd_helper.interfaces): + port_num = self.vnfd_helper.port_num(pname) + port_stats = stats.get(port_num, {}) + samples[pname] = { + 'rx_throughput_fps': float(port_stats.get('rx_pps', 0.0)), + 'tx_throughput_fps': float(port_stats.get('tx_pps', 0.0)), + 'rx_throughput_bps': float(port_stats.get('rx_bps', 0.0)), + 'tx_throughput_bps': float(port_stats.get('tx_bps', 0.0)), + 'in_packets': int(port_stats.get('ipackets', 0)), + 'out_packets': int(port_stats.get('opackets', 0)), + } + + pg_id_list = port_pg_id.get_pg_ids(port_num) + samples[pname]['latency'] = {} + for pg_id in pg_id_list: + latency_global = stats.get('latency', {}) + pg_latency = latency_global.get(pg_id, {}).get('latency') + samples[pname]['latency'][pg_id] = pg_latency + + return samples + class TrexTrafficGen(SampleVNFTrafficGen): """ @@ -174,15 +198,14 @@ class TrexTrafficGen(SampleVNFTrafficGen): APP_NAME = 'TRex' - def __init__(self, name, vnfd, setup_env_helper_type=None, resource_helper_type=None): + def __init__(self, name, vnfd, task_id, setup_env_helper_type=None, + resource_helper_type=None): if resource_helper_type is None: resource_helper_type = TrexResourceHelper - if setup_env_helper_type is None: setup_env_helper_type = TrexDpdkVnfSetupEnvHelper - - super(TrexTrafficGen, self).__init__(name, vnfd, setup_env_helper_type, - resource_helper_type) + super(TrexTrafficGen, self).__init__( + name, vnfd, task_id, setup_env_helper_type, resource_helper_type) def _check_status(self): return self.resource_helper.check_status() diff --git a/yardstick/network_services/vnf_generic/vnf/udp_replay.py b/yardstick/network_services/vnf_generic/vnf/udp_replay.py index a57f53bc7..e3fde1a79 100644 --- a/yardstick/network_services/vnf_generic/vnf/udp_replay.py +++ b/yardstick/network_services/vnf_generic/vnf/udp_replay.py @@ -19,7 +19,7 @@ from yardstick.common.process import check_if_process_failed from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNF from yardstick.network_services.vnf_generic.vnf.sample_vnf import DpdkVnfSetupEnvHelper from yardstick.network_services.vnf_generic.vnf.sample_vnf import ClientResourceHelper - +from yardstick.benchmark.contexts import base as ctx_base LOG = logging.getLogger(__name__) @@ -60,15 +60,14 @@ class UdpReplayApproxVnf(SampleVNF): PIPELINE_COMMAND = REPLAY_PIPELINE_COMMAND - def __init__(self, name, vnfd, setup_env_helper_type=None, resource_helper_type=None): + def __init__(self, name, vnfd, task_id, setup_env_helper_type=None, + resource_helper_type=None): if resource_helper_type is None: resource_helper_type = UdpReplayResourceHelper - if setup_env_helper_type is None: setup_env_helper_type = UdpReplaySetupEnvHelper - - super(UdpReplayApproxVnf, self).__init__(name, vnfd, setup_env_helper_type, - resource_helper_type) + super(UdpReplayApproxVnf, self).__init__( + name, vnfd, task_id, setup_env_helper_type, resource_helper_type) def _build_pipeline_kwargs(self): ports = self.vnfd_helper.port_pairs.all_ports @@ -79,9 +78,11 @@ class UdpReplayApproxVnf(SampleVNF): ports_mask_hex = hex(sum(2 ** num for num in port_nums)) # one core extra for master cpu_mask_hex = hex(2 ** (number_of_ports + 1) - 1) + nfvi_context = ctx_base.Context.get_context_from_server( + self.scenario_helper.nodes[self.name]) hw_csum = "" if (not self.scenario_helper.options.get('hw_csum', False) or - self.nfvi_context.attrs.get('nfvi_type') not in self.HW_OFFLOADING_NFVI_TYPES): + nfvi_context.attrs.get('nfvi_type') not in self.HW_OFFLOADING_NFVI_TYPES): hw_csum = '--no-hw-csum' # tuples of (FLD_PORT, FLD_QUEUE, FLD_LCORE) @@ -116,7 +117,12 @@ class UdpReplayApproxVnf(SampleVNF): stats = self.get_stats() stats_words = stats.split() split_stats = stats_words[stats_words.index('0'):][:number_of_ports * 5] + + physical_node = ctx_base.Context.get_physical_node_from_server( + self.scenario_helper.nodes[self.name]) + result = { + "physical_node": physical_node, "packets_in": get_sum(1), "packets_fwd": get_sum(2), "packets_dropped": get_sum(3) + get_sum(4), diff --git a/yardstick/network_services/vnf_generic/vnf/vfw_vnf.py b/yardstick/network_services/vnf_generic/vnf/vfw_vnf.py index 61e99855f..a1523dee3 100644 --- a/yardstick/network_services/vnf_generic/vnf/vfw_vnf.py +++ b/yardstick/network_services/vnf_generic/vnf/vfw_vnf.py @@ -14,20 +14,19 @@ import logging -from yardstick.common import utils -from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNF, DpdkVnfSetupEnvHelper -from yardstick.network_services.yang_model import YangModel +from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNF +from yardstick.network_services.vnf_generic.vnf.acl_vnf import AclApproxSetupEnvSetupEnvHelper LOG = logging.getLogger(__name__) # vFW should work the same on all systems, we can provide the binary -FW_PIPELINE_COMMAND = """sudo {tool_path} -p {port_mask_hex} -f {cfg_file} -s {script}""" +FW_PIPELINE_COMMAND = "sudo {tool_path} -p {port_mask_hex} -f {cfg_file} -s {script} {hwlb}" FW_COLLECT_KPI = (r"""VFW TOTAL:[^p]+pkts_received"?:\s(\d+),[^p]+pkts_fw_forwarded"?:\s(\d+),""" r"""[^p]+pkts_drop_fw"?:\s(\d+),\s""") -class FWApproxSetupEnvHelper(DpdkVnfSetupEnvHelper): +class FWApproxSetupEnvHelper(AclApproxSetupEnvSetupEnvHelper): APP_NAME = "vFW" CFG_CONFIG = "/tmp/vfw_config" @@ -37,6 +36,8 @@ class FWApproxSetupEnvHelper(DpdkVnfSetupEnvHelper): SW_DEFAULT_CORE = 5 HW_DEFAULT_CORE = 2 VNF_TYPE = "VFW" + RULE_CMD = "vfw" + DEFAULT_FWD_ACTIONS = ["accept", "count", "conntrack"] class FWApproxVnf(SampleVNF): @@ -51,17 +52,9 @@ class FWApproxVnf(SampleVNF): 'packets_dropped': 3, } - def __init__(self, name, vnfd, setup_env_helper_type=None, resource_helper_type=None): + def __init__(self, name, vnfd, task_id, setup_env_helper_type=None, + resource_helper_type=None): if setup_env_helper_type is None: setup_env_helper_type = FWApproxSetupEnvHelper - - super(FWApproxVnf, self).__init__(name, vnfd, setup_env_helper_type, resource_helper_type) - self.vfw_rules = None - - def _start_vnf(self): - yang_model_path = utils.find_relative_file( - self.scenario_helper.options['rules'], - self.scenario_helper.task_path) - yang_model = YangModel(yang_model_path) - self.vfw_rules = yang_model.get_rules() - super(FWApproxVnf, self)._start_vnf() + super(FWApproxVnf, self).__init__( + name, vnfd, task_id, setup_env_helper_type, resource_helper_type) 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 de6fd9329..6c5c6c833 100644 --- a/yardstick/network_services/vnf_generic/vnf/vnf_ssh_helper.py +++ b/yardstick/network_services/vnf_generic/vnf/vnf_ssh_helper.py @@ -47,6 +47,7 @@ class VnfSshHelper(AutoConnectSSH): def upload_config_file(self, prefix, content): cfg_file = os.path.join(constants.REMOTE_TMP, prefix) + LOG.debug('Config file name: %s', cfg_file) LOG.debug(content) file_obj = StringIO(content) self.put_file_obj(file_obj, cfg_file) diff --git a/yardstick/network_services/vnf_generic/vnf/vpe_vnf.py b/yardstick/network_services/vnf_generic/vnf/vpe_vnf.py index 077ce2385..b7cf8b35e 100644 --- a/yardstick/network_services/vnf_generic/vnf/vpe_vnf.py +++ b/yardstick/network_services/vnf_generic/vnf/vpe_vnf.py @@ -28,10 +28,11 @@ from yardstick.common.process import check_if_process_failed from yardstick.network_services.helpers.samplevnf_helper import PortPairs from yardstick.network_services.pipeline import PipelineRules from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNF, DpdkVnfSetupEnvHelper +from yardstick.benchmark.contexts import base as ctx_base LOG = logging.getLogger(__name__) -VPE_PIPELINE_COMMAND = """sudo {tool_path} -p {port_mask_hex} -f {cfg_file} -s {script}""" +VPE_PIPELINE_COMMAND = "sudo {tool_path} -p {port_mask_hex} -f {cfg_file} -s {script} {hwlb}" VPE_COLLECT_KPI = """\ Pkts in:\\s(\\d+)\r\n\ @@ -115,7 +116,8 @@ class ConfigCreate(object): pktq = "SWQ{0}{1}".format(self.sw_q, sink) return pktq - def vpe_upstream(self, vnf_cfg, index=0): + def vpe_upstream(self, vnf_cfg, index=0): # pragma: no cover + # NOTE(ralonsoh): this function must be covered in UTs. parser = configparser.ConfigParser() parser.read(os.path.join(vnf_cfg, 'vpe_upstream')) @@ -147,7 +149,8 @@ class ConfigCreate(object): self.n_pipeline += 1 return parser - def vpe_downstream(self, vnf_cfg, index): + def vpe_downstream(self, vnf_cfg, index): # pragma: no cover + # NOTE(ralonsoh): this function must be covered in UTs. parser = configparser.ConfigParser() parser.read(os.path.join(vnf_cfg, 'vpe_downstream')) for pipeline in parser.sections(): @@ -288,11 +291,12 @@ class VpeApproxVnf(SampleVNF): COLLECT_KPI = VPE_COLLECT_KPI WAIT_TIME = 20 - def __init__(self, name, vnfd, setup_env_helper_type=None, resource_helper_type=None): + def __init__(self, name, vnfd, task_id, setup_env_helper_type=None, + resource_helper_type=None): if setup_env_helper_type is None: setup_env_helper_type = VpeApproxSetupEnvHelper - - super(VpeApproxVnf, self).__init__(name, vnfd, setup_env_helper_type, resource_helper_type) + super(VpeApproxVnf, self).__init__( + name, vnfd, task_id, setup_env_helper_type, resource_helper_type) def get_stats(self, *args, **kwargs): raise NotImplementedError @@ -300,7 +304,11 @@ class VpeApproxVnf(SampleVNF): def collect_kpi(self): # we can't get KPIs if the VNF is down check_if_process_failed(self._vnf_process) + physical_node = ctx_base.Context.get_physical_node_from_server( + self.scenario_helper.nodes[self.name]) + result = { + "physical_node": physical_node, 'pkt_in_up_stream': 0, 'pkt_drop_up_stream': 0, 'pkt_in_down_stream': 0, diff --git a/yardstick/network_services/yang_model.py b/yardstick/network_services/yang_model.py deleted file mode 100644 index ec00c4513..000000000 --- a/yardstick/network_services/yang_model.py +++ /dev/null @@ -1,108 +0,0 @@ -# Copyright (c) 2017 Intel Corporation -# -# 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. - -from __future__ import absolute_import -from __future__ import print_function -import logging -import ipaddress -import six - -from yardstick.common.yaml_loader import yaml_load - -LOG = logging.getLogger(__name__) - - -class YangModel(object): - - RULE_TEMPLATE = "p acl add 1 {0} {1} {2} {3} {4} {5} {6} {7} 0 0 {8}" - - def __init__(self, config_file): - super(YangModel, self).__init__() - self._config_file = config_file - self._options = {} - self._rules = '' - - @property - def config_file(self): - return self._config_file - - @config_file.setter - def config_file(self, value): - self._config_file = value - self._options = {} - self._rules = '' - - def _read_config(self): - # TODO: add some error handling in case of empty or non-existing file - try: - with open(self._config_file) as f: - self._options = yaml_load(f) - except Exception as e: - LOG.exception("Failed to load the yaml %s", e) - raise - - def _get_entries(self): - if not self._options: - return '' - - rule_list = [] - for ace in self._options['access-list1']['acl']['access-list-entries']: - # TODO: resolve ports using topology file and nodes' - # ids: public or private. - matches = ace['ace']['matches'] - dst_ipv4_net = matches['destination-ipv4-network'] - dst_ipv4_net_ip = ipaddress.ip_interface(six.text_type(dst_ipv4_net)) - port0_local_network = dst_ipv4_net_ip.network.network_address.exploded - port0_prefix = dst_ipv4_net_ip.network.prefixlen - - src_ipv4_net = matches['source-ipv4-network'] - src_ipv4_net_ip = ipaddress.ip_interface(six.text_type(src_ipv4_net)) - port1_local_network = src_ipv4_net_ip.network.network_address.exploded - port1_prefix = src_ipv4_net_ip.network.prefixlen - - lower_dport = matches['destination-port-range']['lower-port'] - upper_dport = matches['destination-port-range']['upper-port'] - - lower_sport = matches['source-port-range']['lower-port'] - upper_sport = matches['source-port-range']['upper-port'] - - # TODO: proto should be read from file also. - # Now all rules in sample ACL file are TCP. - rule_list.append('') # get an extra new line - rule_list.append(self.RULE_TEMPLATE.format(port0_local_network, - port0_prefix, - port1_local_network, - port1_prefix, - lower_dport, - upper_dport, - lower_sport, - upper_sport, - 0)) - rule_list.append(self.RULE_TEMPLATE.format(port1_local_network, - port1_prefix, - port0_local_network, - port0_prefix, - lower_sport, - upper_sport, - lower_dport, - upper_dport, - 1)) - - self._rules = '\n'.join(rule_list) - - def get_rules(self): - if not self._rules: - self._read_config() - self._get_entries() - return self._rules diff --git a/yardstick/orchestrator/kubernetes.py b/yardstick/orchestrator/kubernetes.py index 198eeac6d..b0b93a3c2 100644 --- a/yardstick/orchestrator/kubernetes.py +++ b/yardstick/orchestrator/kubernetes.py @@ -7,25 +7,136 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -from __future__ import absolute_import -from __future__ import print_function +import copy +import re -from yardstick.common import utils +from oslo_serialization import jsonutils +import six + +from yardstick.common import constants +from yardstick.common import exceptions from yardstick.common import kubernetes_utils as k8s_utils +from yardstick.common import utils + + +class ContainerObject(object): + + SSH_MOUNT_PATH = '/tmp/.ssh/' + IMAGE_DEFAULT = 'openretriever/yardstick' + COMMAND_DEFAULT = ['/bin/bash', '-c'] + RESOURCES = ('requests', 'limits') + PORT_OPTIONS = ('containerPort', 'hostIP', 'hostPort', 'name', 'protocol') + IMAGE_PULL_POLICY = ('Always', 'IfNotPresent', 'Never') + + def __init__(self, name, ssh_key, **kwargs): + self._name = name + self._ssh_key = ssh_key + self._image = kwargs.get('image', self.IMAGE_DEFAULT) + self._command = self._parse_commands( + kwargs.get('command', self.COMMAND_DEFAULT)) + self._args = self._parse_commands(kwargs.get('args', [])) + self._volume_mounts = kwargs.get('volumeMounts', []) + self._security_context = kwargs.get('securityContext') + self._env = kwargs.get('env', []) + self._resources = kwargs.get('resources', {}) + self._ports = kwargs.get('ports', []) + self._image_pull_policy = kwargs.get('imagePullPolicy') + self._tty = kwargs.get('tty') + self._stdin = kwargs.get('stdin') + + @staticmethod + def _parse_commands(command): + if isinstance(command, six.string_types): + return [command] + elif isinstance(command, list): + return command + raise exceptions.KubernetesContainerCommandType() + + def _create_volume_mounts(self): + """Return all "volumeMounts" items per container""" + volume_mounts_items = [self._create_volume_mounts_item(vol) + for vol in self._volume_mounts] + ssh_vol = {'name': self._ssh_key, + 'mountPath': self.SSH_MOUNT_PATH} + volume_mounts_items.append(self._create_volume_mounts_item(ssh_vol)) + return volume_mounts_items + + @staticmethod + def _create_volume_mounts_item(volume_mount): + """Create a "volumeMounts" item""" + return {'name': volume_mount['name'], + 'mountPath': volume_mount['mountPath'], + 'readOnly': volume_mount.get('readOnly', False)} + + def get_container_item(self): + """Create a "container" item""" + container_name = '{}-container'.format(self._name) + container = {'args': self._args, + 'command': self._command, + 'image': self._image, + 'name': container_name, + 'volumeMounts': self._create_volume_mounts()} + if self._security_context: + container['securityContext'] = self._security_context + if self._env: + container['env'] = [] + for env in self._env: + container['env'].append({'name': env['name'], + 'value': env['value']}) + if self._ports: + container['ports'] = [] + for port in self._ports: + if 'containerPort' not in port.keys(): + raise exceptions.KubernetesContainerPortNotDefined( + port=port) + _port = {port_option: value for port_option, value + in port.items() if port_option in self.PORT_OPTIONS} + container['ports'].append(_port) + if self._resources: + container['resources'] = {} + for res in (res for res in self._resources if + res in self.RESOURCES): + container['resources'][res] = self._resources[res] + if self._image_pull_policy: + if self._image_pull_policy not in self.IMAGE_PULL_POLICY: + raise exceptions.KubernetesContainerWrongImagePullPolicy() + container['imagePullPolicy'] = self._image_pull_policy + if self._stdin is not None: + container['stdin'] = self._stdin + if self._tty is not None: + container['tty'] = self._tty + return container + +class ReplicationControllerObject(object): -class KubernetesObject(object): + SSHKEY_DEFAULT = 'yardstick_key' + RESTART_POLICY = ('Always', 'OnFailure', 'Never') + TOLERATIONS_KEYS = ('key', 'value', 'effect', 'operator') def __init__(self, name, **kwargs): - super(KubernetesObject, self).__init__() + super(ReplicationControllerObject, self).__init__() + parameters = copy.deepcopy(kwargs) self.name = name - self.image = kwargs.get('image', 'openretriever/yardstick') - self.command = [kwargs.get('command', '/bin/bash')] - self.args = kwargs.get('args', []) - self.ssh_key = kwargs.get('ssh_key', 'yardstick_key') - self.node_selector = kwargs.get('nodeSelector', {}) - - self.volumes = [] + self.node_selector = parameters.pop('nodeSelector', {}) + self.ssh_key = parameters.pop('ssh_key', self.SSHKEY_DEFAULT) + self._volumes = parameters.pop('volumes', []) + self._security_context = parameters.pop('securityContext', None) + self._networks = parameters.pop('networks', []) + self._tolerations = parameters.pop('tolerations', []) + self._restart_policy = parameters.pop('restartPolicy', 'Always') + if self._restart_policy not in self.RESTART_POLICY: + raise exceptions.KubernetesWrongRestartPolicy( + rpolicy=self._restart_policy) + + containers = parameters.pop('containers', None) + if containers: + self._containers = [ + ContainerObject(self.name, self.ssh_key, **container) + for container in containers] + else: + self._containers = [ + ContainerObject(self.name, self.ssh_key, **parameters)] self.template = { "apiVersion": "v1", @@ -37,14 +148,14 @@ class KubernetesObject(object): "replicas": 1, "template": { "metadata": { - "labels": { - "app": name - } + "labels": {"app": name} }, "spec": { "containers": [], "volumes": [], - "nodeSelector": {} + "nodeSelector": {}, + "restartPolicy": self._restart_policy, + "tolerations": [] } } } @@ -53,8 +164,14 @@ class KubernetesObject(object): self._change_value_according_name(name) self._add_containers() self._add_node_selector() - self._add_ssh_key_volume() self._add_volumes() + self._add_security_context() + self._add_networks() + self._add_tolerations() + + @property + def networks(self): + return self._networks def get_template(self): return self.template @@ -67,95 +184,291 @@ class KubernetesObject(object): name) def _add_containers(self): - containers = [self._add_container()] + containers = [container.get_container_item() + for container in self._containers] utils.set_dict_value(self.template, 'spec.template.spec.containers', containers) - def _add_container(self): - container_name = '{}-container'.format(self.name) - ssh_key_mount_path = "/root/.ssh/" - - container = { - "args": self.args, - "command": self.command, - "image": self.image, - "name": container_name, - "volumeMounts": [ - { - "mountPath": ssh_key_mount_path, - "name": self.ssh_key - } - ] - } - - return container - def _add_node_selector(self): utils.set_dict_value(self.template, 'spec.template.spec.nodeSelector', self.node_selector) def _add_volumes(self): + """Add "volume" items to container specs, including the SSH one""" + volume_items = [self._create_volume_item(vol) for vol in self._volumes] + volume_items.append(self._create_ssh_key_volume()) utils.set_dict_value(self.template, 'spec.template.spec.volumes', - self.volumes) + volume_items) + + def _create_ssh_key_volume(self): + """Create a "volume" item of type "configMap" for the SSH key""" + return {'name': self.ssh_key, + 'configMap': {'name': self.ssh_key}} + + @staticmethod + def _create_volume_item(volume): + """Create a "volume" item""" + volume = copy.deepcopy(volume) + name = volume.pop('name') + for key in (k for k in volume if k in k8s_utils.get_volume_types()): + type_name = key + type_data = volume[key] + break + else: + raise exceptions.KubernetesTemplateInvalidVolumeType(volume=volume) + + return {'name': name, + type_name: type_data} + + def _add_security_context(self): + if self._security_context: + utils.set_dict_value(self.template, + 'spec.template.spec.securityContext', + self._security_context) + + def _add_networks(self): + networks = [] + for net in self._networks: + networks.append({'name': net}) + + if not networks: + return + + annotations = {'networks': jsonutils.dumps(networks)} + utils.set_dict_value(self.template, + 'spec.template.metadata.annotations', + annotations) - def _add_volume(self, volume): - self.volumes.append(volume) + def _add_tolerations(self): + tolerations = [] + for tol in self._tolerations: + tolerations.append({k: tol[k] for k in tol + if k in self.TOLERATIONS_KEYS}) - def _add_ssh_key_volume(self): - key_volume = { - "configMap": { - "name": self.ssh_key - }, - "name": self.ssh_key - } - self._add_volume(key_volume) + tolerations = ([{'operator': 'Exists'}] if not tolerations + else tolerations) + utils.set_dict_value(self.template, + 'spec.template.spec.tolerations', + tolerations) -class ServiceObject(object): +class ServiceNodePortObject(object): + + MANDATORY_PARAMETERS = {'port', 'name'} + NAME_REGEX = re.compile(r'^[a-z0-9]([-a-z0-9]*[a-z0-9])?$') + + def __init__(self, name, **kwargs): + """Service kind "NodePort" object - def __init__(self, name): - self.name = '{}-service'.format(name) + :param name: (string) name of the Service + :param kwargs: (dict) node_ports -> (list) port, name, targetPort, + nodePort + """ + self._name = '{}-service'.format(name) self.template = { - 'metadata': { - 'name': '{}-service'.format(name) - }, + 'metadata': {'name': '{}-service'.format(name)}, 'spec': { 'type': 'NodePort', - 'ports': [ - { - 'port': 22, - 'protocol': 'TCP' - } - ], - 'selector': { - 'app': name - } + 'ports': [], + 'selector': {'app': name} } } + self._add_port(22, 'ssh', protocol='TCP') + node_ports = copy.deepcopy(kwargs.get('node_ports', [])) + for port in node_ports: + if not self.MANDATORY_PARAMETERS.issubset(port.keys()): + missing_parameters = ', '.join( + str(param) for param in + (self.MANDATORY_PARAMETERS - set(port.keys()))) + raise exceptions.KubernetesServiceObjectDefinitionError( + missing_parameters=missing_parameters) + port_number = port.pop('port') + name = port.pop('name') + if not self.NAME_REGEX.match(name): + raise exceptions.KubernetesServiceObjectNameError(name=name) + self._add_port(port_number, name, **port) + + def _add_port(self, port, name, protocol=None, targetPort=None, + nodePort=None): + _port = {'port': port, + 'name': name} + if protocol: + _port['protocol'] = protocol + if targetPort: + _port['targetPort'] = targetPort + if nodePort: + _port['nodePort'] = nodePort + self.template['spec']['ports'].append(_port) + def create(self): k8s_utils.create_service(self.template) def delete(self): - k8s_utils.delete_service(self.name) + k8s_utils.delete_service(self._name, skip_codes=[404]) + + +class CustomResourceDefinitionObject(object): + + MANDATORY_PARAMETERS = {'name'} + + def __init__(self, ctx_name, **kwargs): + if not self.MANDATORY_PARAMETERS.issubset(kwargs): + missing_parameters = ', '.join( + str(param) for param in + (self.MANDATORY_PARAMETERS - set(kwargs))) + raise exceptions.KubernetesCRDObjectDefinitionError( + missing_parameters=missing_parameters) + + singular = kwargs['name'] + plural = singular + 's' + kind = singular.title() + version = kwargs.get('version', 'v1') + scope = kwargs.get('scope', constants.SCOPE_NAMESPACED) + group = ctx_name + '.com' + self._name = metadata_name = plural + '.' + group + + self._template = { + 'metadata': { + 'name': metadata_name + }, + 'spec': { + 'group': group, + 'version': version, + 'scope': scope, + 'names': {'plural': plural, + 'singular': singular, + 'kind': kind} + } + } + + def create(self): + k8s_utils.create_custom_resource_definition(self._template) + + def delete(self): + k8s_utils.delete_custom_resource_definition(self._name, skip_codes=[404]) + + +class NetworkObject(object): + + MANDATORY_PARAMETERS = {'plugin', 'args'} + KIND = 'Network' + + def __init__(self, name, **kwargs): + if not self.MANDATORY_PARAMETERS.issubset(kwargs): + missing_parameters = ', '.join( + str(param) for param in + (self.MANDATORY_PARAMETERS - set(kwargs))) + raise exceptions.KubernetesNetworkObjectDefinitionError( + missing_parameters=missing_parameters) + + self._name = name + self._plugin = kwargs['plugin'] + self._args = kwargs['args'] + self._crd = None + self._template = None + self._group = None + self._version = None + self._plural = None + self._scope = None + + @property + def crd(self): + if self._crd: + return self._crd + crd = k8s_utils.get_custom_resource_definition(self.KIND) + if not crd: + raise exceptions.KubernetesNetworkObjectKindMissing() + self._crd = crd + return self._crd + + @property + def group(self): + if self._group: + return self._group + self._group = self.crd.spec.group + return self._group + + @property + def version(self): + if self._version: + return self._version + self._version = self.crd.spec.version + return self._version + + @property + def plural(self): + if self._plural: + return self._plural + self._plural = self.crd.spec.names.plural + return self._plural + + @property + def scope(self): + if self._scope: + return self._scope + self._scope = self.crd.spec.scope + return self._scope + + @property + def template(self): + """"Network" object template + + This template can be rendered only once the CRD "Network" is created in + Kubernetes. This function call must be delayed until the creation of + the CRD "Network". + """ + if self._template: + return self._template + + self._template = { + 'apiVersion': '{}/{}'.format(self.group, self.version), + 'kind': self.KIND, + 'metadata': { + 'name': self._name + }, + 'plugin': self._plugin, + 'args': self._args + } + return self._template + + def create(self): + k8s_utils.create_network(self.scope, self.group, self.version, + self.plural, self.template, self._name) + + def delete(self): + k8s_utils.delete_network(self.scope, self.group, self.version, + self.plural, self._name, skip_codes=[404]) class KubernetesTemplate(object): - def __init__(self, name, template_cfg): + def __init__(self, name, context_cfg): + """KubernetesTemplate object initialization + + :param name: (str) name of the Kubernetes context + :param context_cfg: (dict) context definition + """ + context_cfg = copy.deepcopy(context_cfg) + servers_cfg = context_cfg.pop('servers', {}) + crd_cfg = context_cfg.pop('custom_resources', []) + networks_cfg = context_cfg.pop('networks', {}) self.name = name self.ssh_key = '{}-key'.format(name) - self.rcs = [self._get_rc_name(rc) for rc in template_cfg] - self.k8s_objs = [KubernetesObject(self._get_rc_name(rc), - ssh_key=self.ssh_key, - **cfg) - for rc, cfg in template_cfg.items()] - self.service_objs = [ServiceObject(s) for s in self.rcs] - + self.rcs = {self._get_rc_name(rc): cfg + for rc, cfg in servers_cfg.items()} + self.rc_objs = [ReplicationControllerObject( + rc, ssh_key=self.ssh_key, **cfg) for rc, cfg in self.rcs.items()] + self.service_objs = [ServiceNodePortObject(rc, **cfg) + for rc, cfg in self.rcs.items()] + self.crd = [CustomResourceDefinitionObject(self.name, **crd) + for crd in crd_cfg] + self.network_objs = [NetworkObject(net_name, **net_data) + for net_name, net_data in networks_cfg.items()] self.pods = [] def _get_rc_name(self, rc_name): @@ -167,3 +480,8 @@ class KubernetesTemplate(object): if p.metadata.name.startswith(s)] return self.pods + + def get_rc_by_name(self, rc_name): + """Returns a ``ReplicationControllerObject``, searching by name""" + for rc in (rc for rc in self.rc_objs if rc.name == rc_name): + return rc diff --git a/yardstick/service/environment.py b/yardstick/service/environment.py index 324589f79..d910e31e9 100644 --- a/yardstick/service/environment.py +++ b/yardstick/service/environment.py @@ -36,7 +36,7 @@ class Environment(Service): return self._format_sut_info(sut_info) - def _load_pod_info(self): + def _load_pod_info(self): # pragma: no cover if self.pod is None: raise MissingPodInfoError @@ -51,10 +51,10 @@ class Environment(Service): except (ValueError, KeyError): raise UnsupportedPodFormatError - def _format_sut_info(self, sut_info): + def _format_sut_info(self, sut_info): # pragma: no cover return {k: self._format_node_info(v) for k, v in sut_info.items()} - def _format_node_info(self, node_info): + def _format_node_info(self, node_info): # pragma: no cover info = [] facts = node_info.get('ansible_facts', {}) @@ -93,9 +93,9 @@ class Environment(Service): return info - def _get_interface_info(self, facts, name): + def _get_interface_info(self, facts, name): # pragma: no cover mac = facts.get('ansible_{}'.format(name), {}).get('macaddress') return [name, mac] if mac else [] - def _get_device_info(self, name, info): + def _get_device_info(self, name, info): # pragma: no cover return ['disk_{}'.format(name), info.get('size')] diff --git a/yardstick/ssh.py b/yardstick/ssh.py index d7adc0d05..8bdc32c7c 100644 --- a/yardstick/ssh.py +++ b/yardstick/ssh.py @@ -62,15 +62,13 @@ Eventlet: sshclient = eventlet.import_patched("yardstick.ssh") """ -from __future__ import absolute_import -import os import io +import logging +import os +import re import select import socket import time -import re - -import logging import paramiko from chainmap import ChainMap @@ -78,6 +76,7 @@ from oslo_utils import encodeutils from scp import SCPClient import six +from yardstick.common import exceptions from yardstick.common.utils import try_int, NON_NONE_DEFAULT, make_dict_from_map from yardstick.network_services.utils import provision_tool @@ -90,12 +89,12 @@ def convert_key_to_str(key): return k.getvalue() -class SSHError(Exception): - pass - - -class SSHTimeout(SSHError): - pass +# class SSHError(Exception): +# pass +# +# +# class SSHTimeout(SSHError): +# pass class SSH(object): @@ -193,7 +192,7 @@ class SSH(object): return key_class.from_private_key(key) except paramiko.SSHException as e: errors.append(e) - raise SSHError("Invalid pkey: %s" % errors) + raise exceptions.SSHError(error_msg='Invalid pkey: %s' % errors) @property def is_connected(self): @@ -214,10 +213,10 @@ class SSH(object): return self._client except Exception as e: message = ("Exception %(exception_type)s was raised " - "during connect. Exception value is: %(exception)r") + "during connect. Exception value is: %(exception)r" % + {"exception": e, "exception_type": type(e)}) self._client = False - raise SSHError(message % {"exception": e, - "exception_type": type(e)}) + raise exceptions.SSHError(error_msg=message) def _make_dict(self): return { @@ -334,11 +333,11 @@ class SSH(object): break if timeout and (time.time() - timeout) > start_time: - args = {"cmd": cmd, "host": self.host} - raise SSHTimeout("Timeout executing command " - "'%(cmd)s' on host %(host)s" % args) + message = ('Timeout executing command %(cmd)s on host %(host)s' + % {"cmd": cmd, "host": self.host}) + raise exceptions.SSHTimeout(error_msg=message) if e: - raise SSHError("Socket error.") + raise exceptions.SSHError(error_msg='Socket error') exit_status = session.recv_exit_status() if exit_status != 0 and raise_on_error: @@ -346,15 +345,17 @@ class SSH(object): details = fmt % {"cmd": cmd, "status": exit_status} if stderr_data: details += " Last stderr data: '%s'." % stderr_data - raise SSHError(details) + raise exceptions.SSHError(error_msg=details) return exit_status - def execute(self, cmd, stdin=None, timeout=3600): + def execute(self, cmd, stdin=None, timeout=3600, raise_on_error=False): """Execute the specified command on the server. - :param cmd: Command to be executed. - :param stdin: Open file to be sent on process stdin. - :param timeout: Timeout for execution of the command. + :param cmd: (str) Command to be executed. + :param stdin: (StringIO) Open file to be sent on process stdin. + :param timeout: (int) Timeout for execution of the command. + :param raise_on_error: (bool) If True, then an SSHError will be raised + when non-zero exit code. :returns: tuple (exit_status, stdout, stderr) """ @@ -363,7 +364,7 @@ class SSH(object): exit_status = self.run(cmd, stderr=stderr, stdout=stdout, stdin=stdin, - timeout=timeout, raise_on_error=False) + timeout=timeout, raise_on_error=raise_on_error) stdout.seek(0) stderr.seek(0) return exit_status, stdout.read(), stderr.read() @@ -377,11 +378,12 @@ class SSH(object): while True: try: return self.execute("uname") - except (socket.error, SSHError) as e: + except (socket.error, exceptions.SSHError) as e: self.log.debug("Ssh is still unavailable: %r", e) time.sleep(interval) if time.time() > end_time: - raise SSHTimeout("Timeout waiting for '%s'" % self.host) + raise exceptions.SSHTimeout( + error_msg='Timeout waiting for "%s"' % self.host) def put(self, files, remote_path=b'.', recursive=False): client = self._get_client() @@ -486,19 +488,21 @@ class AutoConnectSSH(SSH): while True: try: return self._get_client() - except (socket.error, SSHError) as e: + except (socket.error, exceptions.SSHError) as e: self.log.debug("Ssh is still unavailable: %r", e) time.sleep(interval) if time.time() > end_time: - raise SSHTimeout("Timeout waiting for '%s'" % self.host) + raise exceptions.SSHTimeout( + error_msg='Timeout waiting for "%s"' % self.host) def drop_connection(self): """ Don't close anything, just force creation of a new client """ self._client = False - def execute(self, cmd, stdin=None, timeout=3600): + def execute(self, cmd, stdin=None, timeout=3600, raise_on_error=False): self._connect() - return super(AutoConnectSSH, self).execute(cmd, stdin, timeout) + return super(AutoConnectSSH, self).execute(cmd, stdin, timeout, + raise_on_error) def run(self, cmd, stdin=None, stdout=None, stderr=None, raise_on_error=True, timeout=3600, diff --git a/yardstick/tests/functional/common/messaging/test_messaging.py b/yardstick/tests/functional/common/messaging/test_messaging.py index 99874343b..f3e31e718 100644 --- a/yardstick/tests/functional/common/messaging/test_messaging.py +++ b/yardstick/tests/functional/common/messaging/test_messaging.py @@ -32,25 +32,25 @@ class DummyPayload(payloads.Payload): class DummyEndpoint(consumer.NotificationHandler): def info(self, ctxt, **kwargs): - if ctxt['pid'] in self._ctx_pids: - self._queue.put('ID {}, data: {}, pid: {}'.format( - self._id, kwargs['data'], ctxt['pid'])) + if ctxt['id'] in self._ctx_ids: + self._queue.put('Nr {}, data: {}, id: {}'.format( + self._id, kwargs['data'], ctxt['id'])) class DummyConsumer(consumer.MessagingConsumer): - def __init__(self, _id, ctx_pids, queue): + def __init__(self, _id, ctx_ids, queue): self._id = _id - endpoints = [DummyEndpoint(_id, ctx_pids, queue)] - super(DummyConsumer, self).__init__(TOPIC, ctx_pids, endpoints) + endpoints = [DummyEndpoint(_id, ctx_ids, queue)] + super(DummyConsumer, self).__init__(TOPIC, ctx_ids, endpoints) class DummyProducer(producer.MessagingProducer): pass -def _run_consumer(_id, ctx_pids, queue): - _consumer = DummyConsumer(_id, ctx_pids, queue) +def _run_consumer(_id, ctx_ids, queue): + _consumer = DummyConsumer(_id, ctx_ids, queue) _consumer.start_rpc_server() _consumer.wait() @@ -67,8 +67,8 @@ class MessagingTestCase(base.BaseFunctionalTestCase): num_consumers = 10 ctx_1 = 100001 ctx_2 = 100002 - producers = [DummyProducer(TOPIC, pid=ctx_1), - DummyProducer(TOPIC, pid=ctx_2)] + producers = [DummyProducer(TOPIC, _id=ctx_1), + DummyProducer(TOPIC, _id=ctx_2)] processes = [] for i in range(num_consumers): @@ -91,7 +91,7 @@ class MessagingTestCase(base.BaseFunctionalTestCase): output.append(output_queue.get(True, 1)) self.assertEqual(num_consumers * 4, len(output)) - msg_template = 'ID {}, data: {}, pid: {}' + msg_template = 'Nr {}, data: {}, id: {}' for i in range(num_consumers): for ctx in [ctx_1, ctx_2]: for message in ['message 0', 'message 1']: diff --git a/yardstick/tests/functional/common/test_utils.py b/yardstick/tests/functional/common/test_utils.py index b5333bbde..b9f1f773a 100644 --- a/yardstick/tests/functional/common/test_utils.py +++ b/yardstick/tests/functional/common/test_utils.py @@ -12,8 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. +import multiprocessing import unittest +import socket import sys +import time from yardstick.common import utils @@ -32,3 +35,38 @@ class ImportModulesFromPackageTestCase(unittest.TestCase): library_obj = getattr(module_obj, library_name) class_obj = getattr(library_obj, class_name) self.assertEqual(class_name, class_obj().__class__.__name__) + + +class SendSocketCommandTestCase(unittest.TestCase): + + @staticmethod + def _run_socket_server(port): + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.bind(('localhost', port)) + sock.listen(1) + conn = None + while not conn: + conn, _ = sock.accept() + sock.close() + + @staticmethod + def _terminate_server(socket_server): + # Wait until the socket server closes the open port. + time.sleep(1) + if socket_server and socket_server.is_alive(): + socket_server.terminate() + + def test_send_command(self): + port = 47001 + + socket_server = multiprocessing.Process( + name='run_socket_server', + target=SendSocketCommandTestCase._run_socket_server, + args=(port, )).start() + + self.addCleanup(self._terminate_server, socket_server) + + # Wait until the socket is open. + time.sleep(0.5) + self.assertEqual( + 0, utils.send_socket_command('localhost', port, 'test_command')) diff --git a/tests/unit/network_services/vnf_generic/__init__.py b/yardstick/tests/functional/network_services/__init__.py index e69de29bb..e69de29bb 100644 --- a/tests/unit/network_services/vnf_generic/__init__.py +++ b/yardstick/tests/functional/network_services/__init__.py diff --git a/tests/unit/network_services/vnf_generic/vnf/__init__.py b/yardstick/tests/functional/network_services/vnf_generic/__init__.py index e69de29bb..e69de29bb 100644 --- a/tests/unit/network_services/vnf_generic/vnf/__init__.py +++ b/yardstick/tests/functional/network_services/vnf_generic/__init__.py diff --git a/yardstick/network_services/libs/ixia_libs/IxNet/__init__.py b/yardstick/tests/functional/network_services/vnf_generic/vnf/__init__.py index e69de29bb..e69de29bb 100644 --- a/yardstick/network_services/libs/ixia_libs/IxNet/__init__.py +++ b/yardstick/tests/functional/network_services/vnf_generic/vnf/__init__.py diff --git a/yardstick/tests/functional/network_services/vnf_generic/vnf/test_base.py b/yardstick/tests/functional/network_services/vnf_generic/vnf/test_base.py new file mode 100644 index 000000000..e57f8f51c --- /dev/null +++ b/yardstick/tests/functional/network_services/vnf_generic/vnf/test_base.py @@ -0,0 +1,103 @@ +# Copyright (c) 2018 Intel Corporation +# +# 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. + +import multiprocessing +import time +import uuid + +import mock + +from yardstick.common import messaging +from yardstick.common.messaging import payloads +from yardstick.common.messaging import producer +from yardstick.network_services.vnf_generic.vnf import base as vnf_base +from yardstick.tests.functional import base as ft_base + + +class _TrafficGenMQConsumer(vnf_base.GenericTrafficGen, + vnf_base.GenericVNFEndpoint): + + def __init__(self, name, vnfd, task_id): + vnf_base.GenericTrafficGen.__init__(self, name, vnfd, task_id) + self.queue = multiprocessing.Queue() + self._id = uuid.uuid1().int + vnf_base.GenericVNFEndpoint.__init__(self, self._id, [task_id], + self.queue) + self._consumer = vnf_base.GenericVNFConsumer([task_id], self) + self._consumer.start_rpc_server() + + def run_traffic(self, *args): + pass + + def terminate(self): + pass + + def collect_kpi(self): + pass + + def instantiate(self, *args): + pass + + def scale(self, flavor=''): + pass + + def runner_method_start_iteration(self, ctxt, **kwargs): + if ctxt['id'] in self._ctx_ids: + self._queue.put( + {'action': messaging.RUNNER_METHOD_START_ITERATION, + 'payload': payloads.RunnerPayload.dict_to_obj(kwargs)}) + + def runner_method_stop_iteration(self, ctxt, **kwargs): + if ctxt['id'] in self._ctx_ids: + self._queue.put( + {'action': messaging.RUNNER_METHOD_STOP_ITERATION, + 'payload': payloads.RunnerPayload.dict_to_obj(kwargs)}) + + +class _DummyProducer(producer.MessagingProducer): + pass + + +class GenericVNFMQConsumerTestCase(ft_base.BaseFunctionalTestCase): + + def test_fistro(self): + vnfd = {'benchmark': {'kpi': mock.ANY}, + 'vdu': [{'external-interface': 'ext_int'}] + } + task_id = uuid.uuid1().int + tg_obj = _TrafficGenMQConsumer('name_tg', vnfd, task_id) + producer = _DummyProducer(messaging.TOPIC_RUNNER, task_id) + + num_messages = 10 + for i in range(num_messages): + pload = payloads.RunnerPayload(version=10, data=i) + for method in (messaging.RUNNER_METHOD_START_ITERATION, + messaging.RUNNER_METHOD_STOP_ITERATION): + producer.send_message(method, pload) + + time.sleep(0.5) # Let consumers attend the calls + output = [] + while not tg_obj.queue.empty(): + data = tg_obj.queue.get(True, 1) + data_dict = {'action': data['action'], + 'payload': data['payload'].obj_to_dict()} + output.append(data_dict) + + self.assertEqual(num_messages * 2, len(output)) + for i in range(num_messages): + pload = payloads.RunnerPayload(version=10, data=i).obj_to_dict() + for method in (messaging.RUNNER_METHOD_START_ITERATION, + messaging.RUNNER_METHOD_STOP_ITERATION): + reg = {'action': method, 'payload': pload} + self.assertIn(reg, output) diff --git a/yardstick/tests/unit/apiserver/utils/__init__.py b/yardstick/tests/unit/apiserver/utils/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/yardstick/tests/unit/apiserver/utils/__init__.py diff --git a/yardstick/tests/unit/apiserver/utils/test_influx.py b/yardstick/tests/unit/apiserver/utils/test_influx.py index dce6c1cec..6021d35df 100644 --- a/yardstick/tests/unit/apiserver/utils/test_influx.py +++ b/yardstick/tests/unit/apiserver/utils/test_influx.py @@ -6,28 +6,50 @@ # which accompanies this distribution, and is available at # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -import unittest + +from influxdb import client as influxdb_client import mock +from six.moves import configparser from api.utils import influx -from six.moves import configparser as ConfigParser +from yardstick.common import constants +from yardstick.common import exceptions +from yardstick import dispatcher +from yardstick.tests.unit import base + +class GetDataDbClientTestCase(base.BaseUnitTestCase): -class GetDataDbClientTestCase(unittest.TestCase): + @mock.patch.object(influx, '_get_influxdb_client', + return_value='fake_client') + @mock.patch.object(influx.ConfigParser, 'ConfigParser') + def test_get_data_db_client(self, mock_parser, mock_get_client): + _mock_parser = mock.Mock() + mock_parser.return_value = _mock_parser - @mock.patch('api.utils.influx.ConfigParser') - def test_get_data_db_client_dispatcher_not_influxdb(self, mock_parser): - mock_parser.ConfigParser().get.return_value = 'file' - # reset exception to avoid - # TypeError: catching classes that do not inherit from BaseException - mock_parser.NoOptionError = ConfigParser.NoOptionError - try: + self.assertEqual('fake_client', influx.get_data_db_client()) + _mock_parser.read.assert_called_once_with(constants.CONF_FILE) + mock_get_client.assert_called_once_with(_mock_parser) + + @mock.patch.object(influx.logger, 'error') + @mock.patch.object(influx, '_get_influxdb_client', + return_value='fake_client') + @mock.patch.object(influx.ConfigParser, 'ConfigParser') + def test_get_data_db_client_parsing_error( + self, mock_parser, mock_get_client, *args): + _mock_parser = mock.Mock() + mock_parser.return_value = _mock_parser + mock_parser.NoOptionError = configparser.NoOptionError + mock_get_client.side_effect = configparser.NoOptionError('option', + 'section') + with self.assertRaises(configparser.NoOptionError): influx.get_data_db_client() - except Exception as e: # pylint: disable=broad-except - self.assertIsInstance(e, RuntimeError) + + _mock_parser.read.assert_called_once_with(constants.CONF_FILE) + mock_get_client.assert_called_once_with(_mock_parser) -class GetIpTestCase(unittest.TestCase): +class GetIpTestCase(base.BaseUnitTestCase): def test_get_url(self): url = 'http://localhost:8086/hello' @@ -37,16 +59,32 @@ class GetIpTestCase(unittest.TestCase): self.assertEqual(result, output) -class QueryTestCase(unittest.TestCase): +class GetInfluxdbTestCase(base.BaseUnitTestCase): + + @mock.patch.object(influxdb_client, 'InfluxDBClient', + return_value='idb_client') + @mock.patch.object(influx, '_get_ip', return_value='fake_ip') + def test_get_influxdb_client(self, mock_get_ip, mock_client): + mock_parser = mock.Mock() + mock_parser.get.side_effect = [dispatcher.INFLUXDB, 'target', 'user', + 'pass', 'db_name'] + + self.assertEqual('idb_client', + influx._get_influxdb_client(mock_parser)) + mock_client.assert_called_once_with('fake_ip', constants.INFLUXDB_PORT, + 'user', 'pass', 'db_name') + mock_get_ip.assert_called_once_with('target') + mock_parser.get.assert_has_calls([ + mock.call('DEFAULT', 'dispatcher'), + mock.call('dispatcher_influxdb', 'target'), + mock.call('dispatcher_influxdb', 'username'), + mock.call('dispatcher_influxdb', 'password'), + mock.call('dispatcher_influxdb', 'db_name')]) + + def test_get_influxdb_client_no_influxdb_client(self): + mock_parser = mock.Mock() + mock_parser.get.return_value = dispatcher.FILE - @mock.patch('api.utils.influx.ConfigParser') - def test_query_dispatcher_not_influxdb(self, mock_parser): - mock_parser.ConfigParser().get.return_value = 'file' - # reset exception to avoid - # TypeError: catching classes that do not inherit from BaseException - mock_parser.NoOptionError = ConfigParser.NoOptionError - try: - sql = 'select * form tasklist' - influx.query(sql) - except Exception as e: # pylint: disable=broad-except - self.assertIsInstance(e, RuntimeError) + with self.assertRaises(exceptions.InfluxDBConfigurationMissing): + influx._get_influxdb_client(mock_parser) + mock_parser.get.assert_called_once_with('DEFAULT', 'dispatcher') diff --git a/yardstick/tests/unit/benchmark/contexts/standalone/test_model.py b/yardstick/tests/unit/benchmark/contexts/standalone/test_model.py index 72e684a68..8ad581918 100644 --- a/yardstick/tests/unit/benchmark/contexts/standalone/test_model.py +++ b/yardstick/tests/unit/benchmark/contexts/standalone/test_model.py @@ -371,11 +371,6 @@ class StandaloneContextHelperTestCase(unittest.TestCase): file_path = os.path.join(curr_path, filename) return file_path - def test_read_config_file(self): - self.helper.file_path = self._get_file_abspath(self.NODE_SAMPLE) - status = self.helper.read_config_file() - self.assertIsNotNone(status) - def test_parse_pod_file(self): self.helper.file_path = self._get_file_abspath("dummy") self.assertRaises(IOError, self.helper.parse_pod_file, @@ -550,4 +545,4 @@ class OvsDeployTestCase(unittest.TestCase): 'dpdk_version': dpdk_version, 'proxy': 'test_proxy'}) mock_execute.assert_called_once_with(cmd) - mock_env_get.assert_called_once_with('http_proxy', '') + mock_env_get.assert_has_calls([mock.call('http_proxy', '')]) diff --git a/yardstick/tests/unit/benchmark/contexts/standalone/test_ovs_dpdk.py b/yardstick/tests/unit/benchmark/contexts/standalone/test_ovs_dpdk.py index bc3bb73cd..69779d3e0 100644 --- a/yardstick/tests/unit/benchmark/contexts/standalone/test_ovs_dpdk.py +++ b/yardstick/tests/unit/benchmark/contexts/standalone/test_ovs_dpdk.py @@ -19,6 +19,8 @@ import mock import six import unittest +from yardstick.benchmark import contexts +from yardstick.benchmark.contexts import base from yardstick.benchmark.contexts.standalone import model from yardstick.benchmark.contexts.standalone import ovs_dpdk from yardstick.common import exceptions @@ -57,11 +59,19 @@ class OvsDpdkContextTestCase(unittest.TestCase): 'file': self._get_file_abspath(self.NODES_ovs_dpdk_SAMPLE) } self.ovs_dpdk = ovs_dpdk.OvsDpdkContext() + self._mock_log = mock.patch.object(ovs_dpdk, 'LOG') + self.mock_log = self._mock_log.start() self.addCleanup(self._remove_contexts) + self.addCleanup(self._stop_mocks) - def _remove_contexts(self): - if self.ovs_dpdk in self.ovs_dpdk.list: - self.ovs_dpdk._delete_context() + @staticmethod + def _remove_contexts(): + for context in base.Context.list: + context._delete_context() + base.Context.list = [] + + def _stop_mocks(self): + self._mock_log.stop() @mock.patch('yardstick.benchmark.contexts.standalone.model.Server') @mock.patch('yardstick.benchmark.contexts.standalone.model.StandaloneContextHelper') @@ -73,7 +83,7 @@ class OvsDpdkContextTestCase(unittest.TestCase): def test_init(self): ATTRS = { - 'name': 'StandaloneOvsDpdk', + 'name': contexts.CONTEXT_STANDALONEOVSDPDK, 'task_id': '1234567890', 'file': 'pod', 'flavor': {}, @@ -287,6 +297,22 @@ class OvsDpdkContextTestCase(unittest.TestCase): self.assertEqual(result['user'], 'root') self.assertEqual(result['key_filename'], '/root/.yardstick_key') + def test__get_physical_node_for_server(self): + attrs = self.attrs + attrs.update({'servers': {'server1': {}}}) + self.ovs_dpdk.init(attrs) + + # When server is not from this context + result = self.ovs_dpdk._get_physical_node_for_server('server1.another-context') + self.assertIsNone(result) + + # When node_name is not from this context + result = self.ovs_dpdk._get_physical_node_for_server('fake.foo-12345678') + self.assertIsNone(result) + + result = self.ovs_dpdk._get_physical_node_for_server('server1.foo-12345678') + self.assertEqual(result, 'node5.foo') + # TODO(elfoley): Split this test for networks that exist and networks that # don't def test__get_network(self): diff --git a/yardstick/tests/unit/benchmark/contexts/standalone/test_sriov.py b/yardstick/tests/unit/benchmark/contexts/standalone/test_sriov.py index e70ab0ae8..74c31569c 100644 --- a/yardstick/tests/unit/benchmark/contexts/standalone/test_sriov.py +++ b/yardstick/tests/unit/benchmark/contexts/standalone/test_sriov.py @@ -18,6 +18,8 @@ import mock import unittest from yardstick import ssh +from yardstick.benchmark import contexts +from yardstick.benchmark.contexts import base from yardstick.benchmark.contexts.standalone import model from yardstick.benchmark.contexts.standalone import sriov @@ -29,7 +31,7 @@ class SriovContextTestCase(unittest.TestCase): NODES_DUPLICATE_SAMPLE = "nodes_duplicate_sample.yaml" ATTRS = { - 'name': 'StandaloneSriov', + 'name': contexts.CONTEXT_STANDALONESRIOV, 'task_id': '1234567890', 'file': 'pod', 'flavor': {}, @@ -61,14 +63,16 @@ class SriovContextTestCase(unittest.TestCase): self.attrs = { 'name': 'foo', 'task_id': '1234567890', - 'file': self._get_file_abspath(self.NODES_SRIOV_SAMPLE) + 'file': self._get_file_abspath(self.NODES_SRIOV_SAMPLE), } self.sriov = sriov.SriovContext() self.addCleanup(self._remove_contexts) - def _remove_contexts(self): - if self.sriov in self.sriov.list: - self.sriov._delete_context() + @staticmethod + def _remove_contexts(): + for context in base.Context.list: + context._delete_context() + base.Context.list = [] @mock.patch.object(model, 'StandaloneContextHelper') @mock.patch.object(model, 'Libvirt') @@ -168,6 +172,22 @@ class SriovContextTestCase(unittest.TestCase): self.assertEqual(result['user'], 'root') self.assertEqual(result['key_filename'], '/root/.yardstick_key') + def test__get_physical_node_for_server(self): + attrs = self.attrs + attrs.update({'servers': {'server1': {}}}) + self.sriov.init(attrs) + + # When server is not from this context + result = self.sriov._get_physical_node_for_server('server1.another-context') + self.assertIsNone(result) + + # When node_name is not from this context + result = self.sriov._get_physical_node_for_server('fake.foo-12345678') + self.assertIsNone(result) + + result = self.sriov._get_physical_node_for_server('server1.foo-12345678') + self.assertEqual(result, 'node5.foo') + def test__get_server_no_task_id(self): self.attrs['flags'] = {'no_setup': True} self.sriov.init(self.attrs) @@ -242,18 +262,19 @@ class SriovContextTestCase(unittest.TestCase): self.assertIsNone(self.sriov.configure_nics_for_sriov()) @mock.patch.object(ssh, 'SSH', return_value=(0, "a", "")) - @mock.patch.object(model, 'Libvirt') - def test__enable_interfaces(self, mock_libvirt, mock_ssh): - # pylint: disable=unused-argument - # NOTE(ralonsoh): the pylint exception should be removed. + @mock.patch.object(model.Libvirt, 'add_sriov_interfaces', + return_value='out_xml') + def test__enable_interfaces(self, mock_add_sriov, mock_ssh): self.sriov.vm_deploy = True self.sriov.connection = mock_ssh self.sriov.vm_names = ['vm_0', 'vm_1'] self.sriov.drivers = [] self.sriov.networks = self.NETWORKS - self.sriov.get_vf_data = mock.Mock(return_value="") - self.assertIsNone(self.sriov._enable_interfaces( - 0, 0, ["private_0"], 'test')) + self.assertEqual( + 'out_xml', + self.sriov._enable_interfaces(0, 0, ['private_0'], 'test')) + mock_add_sriov.assert_called_once_with( + '0000:00:0a.0', 0, self.NETWORKS['private_0']['mac'], 'test') @mock.patch.object(model.Libvirt, 'build_vm_xml') @mock.patch.object(model.Libvirt, 'check_if_vm_exists_and_delete') @@ -282,7 +303,9 @@ class SriovContextTestCase(unittest.TestCase): mock_build_vm_xml.return_value = (xml_out, '00:00:00:00:00:01') with mock.patch.object(self.sriov, 'vnf_node') as mock_vnf_node, \ - mock.patch.object(self.sriov, '_enable_interfaces'): + mock.patch.object(self.sriov, '_enable_interfaces') as \ + mock_enable_interfaces: + mock_enable_interfaces.return_value = 'out_xml' mock_vnf_node.generate_vnf_instance = mock.Mock( return_value='node') nodes_out = self.sriov.setup_sriov_context() @@ -294,7 +317,10 @@ class SriovContextTestCase(unittest.TestCase): connection, 'flavor', vm_name, 0) mock_create_vm.assert_called_once_with(connection, cfg) mock_check.assert_called_once_with(vm_name, connection) - mock_write_file.assert_called_once_with(cfg, xml_out) + mock_write_file.assert_called_once_with(cfg, 'out_xml') + mock_enable_interfaces.assert_has_calls([ + mock.call(0, mock.ANY, ['private_0'], mock.ANY), + mock.call(0, mock.ANY, ['public_0'], mock.ANY)], any_order=True) def test__get_vf_data(self): with mock.patch("yardstick.ssh.SSH") as ssh: diff --git a/yardstick/tests/unit/benchmark/contexts/test_base.py b/yardstick/tests/unit/benchmark/contexts/test_base.py index b19883479..5fd7352f5 100644 --- a/yardstick/tests/unit/benchmark/contexts/test_base.py +++ b/yardstick/tests/unit/benchmark/contexts/test_base.py @@ -12,12 +12,50 @@ # See the License for the specific language governing permissions and # limitations under the License. -import unittest +import os +import errno + +import mock from yardstick.benchmark.contexts import base +from yardstick.benchmark.contexts.base import Context +from yardstick.common import yaml_loader +from yardstick.tests.unit import base as ut_base +from yardstick.common.constants import YARDSTICK_ROOT_PATH + + +class DummyContextClass(Context): + + __context_type__ = "Dummy" + + def __init__(self, host_name_separator='.'): + super(DummyContextClass, self).__init__\ + (host_name_separator=host_name_separator) + self.nodes = [] + self.controllers = [] + self.computes = [] + self.baremetals = [] + + def _get_network(self, *args): + pass + + def _get_server(self, *args): + pass + + def deploy(self): + pass + def undeploy(self): + pass -class FlagsTestCase(unittest.TestCase): + def _get_physical_nodes(self): + pass + + def _get_physical_node_for_server(self, server_name): + pass + + +class FlagsTestCase(ut_base.BaseUnitTestCase): def setUp(self): self.flags = base.Flags() @@ -44,3 +82,93 @@ class FlagsTestCase(unittest.TestCase): self.flags.parse(foo=42) with self.assertRaises(AttributeError): _ = self.flags.foo + + +class ContextTestCase(ut_base.BaseUnitTestCase): + + @staticmethod + def _remove_ctx(ctx_obj): + if ctx_obj in base.Context.list: + base.Context.list.remove(ctx_obj) + + def test_split_host_name(self): + ctx_obj = DummyContextClass() + self.addCleanup(self._remove_ctx, ctx_obj) + config_name = 'host_name.ctx_name' + self.assertEqual(('host_name', 'ctx_name'), + ctx_obj.split_host_name(config_name)) + + def test_split_host_name_wrong_separator(self): + ctx_obj = DummyContextClass() + self.addCleanup(self._remove_ctx, ctx_obj) + config_name = 'host_name-ctx_name' + self.assertEqual((None, None), + ctx_obj.split_host_name(config_name)) + + def test_split_host_name_other_separator(self): + ctx_obj = DummyContextClass(host_name_separator='-') + self.addCleanup(self._remove_ctx, ctx_obj) + config_name = 'host_name-ctx_name' + self.assertEqual(('host_name', 'ctx_name'), + ctx_obj.split_host_name(config_name)) + + def test_get_physical_nodes(self): + ctx_obj = DummyContextClass() + self.addCleanup(self._remove_ctx, ctx_obj) + + result = Context.get_physical_nodes() + + self.assertEqual(result, {None: None}) + + @mock.patch.object(Context, 'get_context_from_server') + def test_get_physical_node_from_server(self, mock_get_ctx): + ctx_obj = DummyContextClass() + self.addCleanup(self._remove_ctx, ctx_obj) + + mock_get_ctx.return_value = ctx_obj + + result = Context.get_physical_node_from_server("mock_server") + + mock_get_ctx.assert_called_once() + self.assertIsNone(result) + + @mock.patch.object(yaml_loader, 'read_yaml_file') + def test_read_pod_file(self, mock_read_yaml_file): + attrs = {'name': 'foo', + 'task_id': '12345678', + 'file': 'pod.yaml' + } + + ctx_obj = DummyContextClass() + cfg = {"nodes": [ + { + "name": "node1", + "role": "Controller", + "ip": "10.229.47.137", + "user": "root", + "key_filename": "/root/.yardstick_key" + }, + { + "name": "node2", + "role": "Compute", + "ip": "10.229.47.139", + "user": "root", + "key_filename": "/root/.yardstick_key" + } + ] + } + + mock_read_yaml_file.return_value = cfg + result = ctx_obj.read_pod_file(attrs) + self.assertEqual(result, cfg) + + mock_read_yaml_file.side_effect = IOError(errno.EPERM, '') + with self.assertRaises(IOError): + ctx_obj.read_pod_file(attrs) + + mock_read_yaml_file.side_effect = IOError(errno.ENOENT, '') + with self.assertRaises(IOError): + ctx_obj.read_pod_file(attrs) + + file_path = os.path.join(YARDSTICK_ROOT_PATH, 'pod.yaml') + self.assertEqual(ctx_obj.file_path, file_path) diff --git a/yardstick/tests/unit/benchmark/contexts/test_dummy.py b/yardstick/tests/unit/benchmark/contexts/test_dummy.py index e393001a1..33832375f 100644 --- a/yardstick/tests/unit/benchmark/contexts/test_dummy.py +++ b/yardstick/tests/unit/benchmark/contexts/test_dummy.py @@ -9,6 +9,7 @@ import unittest +from yardstick.benchmark.contexts import base from yardstick.benchmark.contexts import dummy @@ -20,7 +21,12 @@ class DummyContextTestCase(unittest.TestCase): 'task_id': '1234567890', } self.test_context = dummy.DummyContext() - self.addCleanup(self.test_context._delete_context) + self.addCleanup(self._delete_contexts) + + @staticmethod + def _delete_contexts(): + for context in base.Context.list: + context._delete_context() def test___init__(self): self.assertFalse(self.test_context._flags.no_setup) @@ -70,3 +76,11 @@ class DummyContextTestCase(unittest.TestCase): self.assertEqual(result, None) self.test_context.undeploy() + + def test__get_physical_nodes(self): + result = self.test_context._get_physical_nodes() + self.assertIsNone(result) + + def test__get_physical_node_for_server(self): + result = self.test_context._get_physical_node_for_server("fake") + self.assertIsNone(result) diff --git a/yardstick/tests/unit/benchmark/contexts/test_heat.py b/yardstick/tests/unit/benchmark/contexts/test_heat.py index ebb1d69ba..7782d96bd 100644 --- a/yardstick/tests/unit/benchmark/contexts/test_heat.py +++ b/yardstick/tests/unit/benchmark/contexts/test_heat.py @@ -8,7 +8,6 @@ ############################################################################## from collections import OrderedDict -from itertools import count import logging import os @@ -20,6 +19,8 @@ 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.common import openstack_utils +from yardstick.common import yaml_loader from yardstick import ssh @@ -28,9 +29,28 @@ LOG = logging.getLogger(__name__) class HeatContextTestCase(unittest.TestCase): + HEAT_POD_SAMPLE = { + "nodes": [ + { + "name": "node1", + "role": "Controller", + "ip": "10.229.47.137", + "user": "root", + "key_filename": "/root/.yardstick_key" + }, + { + "name": "node2", + "role": "Compute", + "ip": "10.229.47.139", + "user": "root", + "key_filename": "/root/.yardstick_key" + } + ] + } + def __init__(self, *args, **kwargs): + super(HeatContextTestCase, self).__init__(*args, **kwargs) - self.name_iter = ('vnf{:03}'.format(x) for x in count(0, step=3)) def setUp(self): self.test_context = heat.HeatContext() @@ -61,24 +81,30 @@ class HeatContextTestCase(unittest.TestCase): self.assertIsNone(self.test_context.heat_parameters) self.assertIsNone(self.test_context.key_filename) + @mock.patch.object(yaml_loader, 'read_yaml_file') @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): + def test_init(self, mock_server, mock_network, mock_sg, mock_pg, + mock_read_yaml): + mock_read_yaml.return_value = self.HEAT_POD_SAMPLE pgs = {'pgrp1': {'policy': 'availability'}} sgs = {'servergroup1': {'policy': 'affinity'}} networks = {'bar': {'cidr': '10.0.1.0/24'}} servers = {'baz': {'floating_ip': True, 'placement': 'pgrp1'}} attrs = {'name': 'foo', + 'file': 'pod.yaml', 'task_id': '1234567890', 'placement_groups': pgs, 'server_groups': sgs, 'networks': networks, 'servers': servers} - self.test_context.init(attrs) + with mock.patch.object(openstack_utils, 'get_shade_client'), \ + mock.patch.object(openstack_utils, 'get_shade_operator_client'): + self.test_context.init(attrs) self.assertFalse(self.test_context._flags.no_setup) self.assertFalse(self.test_context._flags.no_teardown) @@ -132,13 +158,17 @@ class HeatContextTestCase(unittest.TestCase): 'server_groups': {}, 'networks': {}, 'servers': {}, + 'file': "pod.yaml", 'flags': { 'no_setup': True, 'no_teardown': True, }, } - self.test_context.init(attrs) + with mock.patch.object(openstack_utils, 'get_shade_client'), \ + mock.patch.object(openstack_utils, 'get_shade_operator_client'): + self.test_context.init(attrs) + self.assertTrue(self.test_context._flags.no_setup) self.assertTrue(self.test_context._flags.no_teardown) @@ -725,3 +755,56 @@ class HeatContextTestCase(unittest.TestCase): } result = self.test_context._get_network(attr_name) self.assertDictEqual(result, expected) + + def _get_file_abspath(self, filename): + curr_path = os.path.dirname(os.path.abspath(__file__)) + file_path = os.path.join(curr_path, filename) + return file_path + + def test__get_physical_nodes(self): + self.test_context.nodes = {} + nodes = self.test_context._get_physical_nodes() + self.assertEquals(nodes, {}) + + @mock.patch.object(yaml_loader, 'read_yaml_file') + def test__get_physical_node_for_server(self, mock_read_yaml): + attrs = {'name': 'foo', + 'task_id': '12345678', + 'file': "pod.yaml", + 'servers': {'vnf': {}}, + 'networks': {'mgmt': {'cidr': '10.0.1.0/24'}} + } + + with mock.patch.object(openstack_utils, 'get_shade_client'), \ + mock.patch.object(openstack_utils, 'get_shade_operator_client'): + mock_read_yaml.return_value = self.HEAT_POD_SAMPLE + self.test_context.init(attrs) + + with mock.patch('yardstick.common.openstack_utils.get_server') as mock_get_server: + mock_get_server.return_value = {'vnf': {}} + + # When server is not from this context + result = self.test_context._get_physical_node_for_server('node1.foo-context') + self.assertIsNone(result) + + # When node_name is not from this context + result = self.test_context._get_physical_node_for_server('fake.foo-12345678') + self.assertIsNone(result) + + mock_munch = mock.Mock() + mock_munch.toDict = mock.Mock(return_value={ + 'OS-EXT-SRV-ATTR:hypervisor_hostname': 'hypervisor_hostname' + }) + mock_get_server.return_value = mock_munch + + hypervisor = mock.Mock() + hypervisor.hypervisor_hostname = 'hypervisor_hostname' + hypervisor.host_ip = '10.229.47.137' + + self.test_context.operator_client.list_hypervisors = mock.Mock( + return_value=[hypervisor]) + + mock_get_server.return_value = mock_munch + + result = self.test_context._get_physical_node_for_server('vnf.foo-12345678') + self.assertEqual(result, 'node1.foo') diff --git a/yardstick/tests/unit/benchmark/contexts/test_kubernetes.py b/yardstick/tests/unit/benchmark/contexts/test_kubernetes.py index 4dd9d40d1..b526e7cc7 100644 --- a/yardstick/tests/unit/benchmark/contexts/test_kubernetes.py +++ b/yardstick/tests/unit/benchmark/contexts/test_kubernetes.py @@ -7,33 +7,74 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## +import collections +import time + import mock import unittest +from yardstick.benchmark import contexts +from yardstick.benchmark.contexts import base from yardstick.benchmark.contexts import kubernetes +from yardstick.common import constants +from yardstick.common import exceptions +from yardstick.common import kubernetes_utils as k8s_utils +from yardstick.orchestrator import kubernetes as orchestrator_kubernetes -context_cfg = { - 'type': 'Kubernetes', +CONTEXT_CFG = { + 'type': contexts.CONTEXT_KUBERNETES, 'name': 'k8s', 'task_id': '1234567890', 'servers': { 'host': { 'image': 'openretriever/yardstick', 'command': '/bin/bash', - 'args': ['-c', 'chmod 700 ~/.ssh; chmod 600 ~/.ssh/*; \ -service ssh restart;while true ; do sleep 10000; done'] + 'args': ['-c', 'chmod 700 ~/.ssh; chmod 600 ~/.ssh/*; ' + 'service ssh restart;while true ; do sleep 10000; done'] }, 'target': { 'image': 'openretriever/yardstick', 'command': '/bin/bash', - 'args': ['-c', 'chmod 700 ~/.ssh; chmod 600 ~/.ssh/*; \ -service ssh restart;while true ; do sleep 10000; done'] + 'args': ['-c', 'chmod 700 ~/.ssh; chmod 600 ~/.ssh/*; ' + 'service ssh restart;while true ; do sleep 10000; done'] } + }, + 'networks': { + 'flannel': { + 'args': 'flannel_args', + 'plugin': 'flannel' + }, + 'sriov01': { + 'args': 'sriov_args', + 'plugin': 'sriov' + }, } } -prefix = 'yardstick.benchmark.contexts.kubernetes' + +class NodePort(object): + def __init__(self): + self.node_port = 30000 + self.port = constants.SSH_PORT + self.name = 'port_name' + self.protocol = 'TCP' + self.target_port = constants.SSH_PORT + + +class Service(object): + def __init__(self): + self.ports = [NodePort()] + + +class Status(object): + def __init__(self): + self.pod_ip = '172.16.10.131' + + +class Pod(object): + def __init__(self): + self.status = Status() class KubernetesTestCase(unittest.TestCase): @@ -41,54 +82,60 @@ class KubernetesTestCase(unittest.TestCase): def setUp(self): self.k8s_context = kubernetes.KubernetesContext() self.addCleanup(self._remove_contexts) - self.k8s_context.init(context_cfg) + self.k8s_context.init(CONTEXT_CFG) - def _remove_contexts(self): - if self.k8s_context in self.k8s_context.list: - self.k8s_context._delete_context() + @staticmethod + def _remove_contexts(): + for context in base.Context.list: + context._delete_context() + base.Context.list = [] @mock.patch.object(kubernetes.KubernetesContext, '_delete_services') @mock.patch.object(kubernetes.KubernetesContext, '_delete_ssh_key') @mock.patch.object(kubernetes.KubernetesContext, '_delete_rcs') @mock.patch.object(kubernetes.KubernetesContext, '_delete_pods') - def test_undeploy(self, - mock_delete_pods, - mock_delete_rcs, - mock_delete_ssh, - mock_delete_services): + @mock.patch.object(kubernetes.KubernetesContext, '_delete_networks') + @mock.patch.object(kubernetes.KubernetesContext, '_delete_crd') + def test_undeploy(self, mock_delete_pods, mock_delete_rcs, + mock_delete_ssh, mock_delete_services, + mock_delete_networks, mock_delete_crd): self.k8s_context.undeploy() 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_delete_networks.assert_called_once() + mock_delete_crd.assert_called_once() @mock.patch.object(kubernetes.KubernetesContext, '_create_services') @mock.patch.object(kubernetes.KubernetesContext, '_wait_until_running') - @mock.patch.object(kubernetes.KubernetesTemplate, 'get_rc_pods') + @mock.patch.object(orchestrator_kubernetes.KubernetesTemplate, + 'get_rc_pods') @mock.patch.object(kubernetes.KubernetesContext, '_create_rcs') @mock.patch.object(kubernetes.KubernetesContext, '_set_ssh_key') - def test_deploy(self, - mock_set_ssh_key, - mock_create_rcs, - mock_get_rc_pods, - mock_wait_until_running, - mock_create_services): - - with mock.patch("yardstick.benchmark.contexts.kubernetes.time"): + @mock.patch.object(kubernetes.KubernetesContext, '_create_networks') + @mock.patch.object(kubernetes.KubernetesContext, '_create_crd') + def test_deploy(self, mock_set_ssh_key, mock_create_rcs, mock_get_rc_pods, + mock_wait_until_running, mock_create_services, + mock_create_networks, mock_create_crd): + + with mock.patch.object(time, 'sleep'): self.k8s_context.deploy() 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_create_networks.assert_called_once() + mock_create_crd.assert_called_once() @mock.patch.object(kubernetes, 'paramiko', **{"resource_filename.return_value": ""}) @mock.patch.object(kubernetes, 'pkg_resources', **{"resource_filename.return_value": ""}) @mock.patch.object(kubernetes, 'utils') @mock.patch.object(kubernetes, 'open', create=True) - @mock.patch.object(kubernetes.k8s_utils, 'delete_config_map') - @mock.patch.object(kubernetes.k8s_utils, 'create_config_map') + @mock.patch.object(k8s_utils, 'delete_config_map') + @mock.patch.object(k8s_utils, 'create_config_map') def test_ssh_key(self, mock_create, mock_delete, *args): self.k8s_context._set_ssh_key() self.k8s_context._delete_ssh_key() @@ -96,49 +143,32 @@ class KubernetesTestCase(unittest.TestCase): mock_create.assert_called_once() mock_delete.assert_called_once() - @mock.patch.object(kubernetes.k8s_utils, 'read_pod_status') + @mock.patch.object(k8s_utils, 'read_pod_status') def test_wait_until_running(self, mock_read_pod_status): self.k8s_context.template.pods = ['server'] mock_read_pod_status.return_value = 'Running' self.k8s_context._wait_until_running() - @mock.patch.object(kubernetes.k8s_utils, 'get_pod_by_name') + @mock.patch.object(k8s_utils, 'get_pod_by_name') @mock.patch.object(kubernetes.KubernetesContext, '_get_node_ip') - @mock.patch.object(kubernetes.k8s_utils, 'get_service_by_name') - def test_get_server(self, - mock_get_service_by_name, - mock_get_node_ip, - mock_get_pod_by_name): - class Service(object): - def __init__(self): - self.name = 'yardstick' - self.node_port = 30000 - - class Services(object): - def __init__(self): - self.ports = [Service()] - - class Status(object): - def __init__(self): - self.pod_ip = '172.16.10.131' - - class Pod(object): - def __init__(self): - self.status = Status() - - mock_get_service_by_name.return_value = Services() + def test_get_server(self, mock_get_node_ip, mock_get_pod_by_name): mock_get_pod_by_name.return_value = Pod() mock_get_node_ip.return_value = '172.16.10.131' - - self.assertIsNotNone(self.k8s_context._get_server('server')) + with mock.patch.object(self.k8s_context, '_get_service_ports') as \ + mock_get_sports: + mock_get_sports.return_value = [ + {'port': constants.SSH_PORT, 'node_port': 30000}] + server = self.k8s_context._get_server('server_name') + self.assertEqual('server_name', server['name']) + self.assertEqual(30000, server['ssh_port']) @mock.patch.object(kubernetes.KubernetesContext, '_create_rc') def test_create_rcs(self, mock_create_rc): self.k8s_context._create_rcs() mock_create_rc.assert_called() - @mock.patch.object(kubernetes.k8s_utils, 'create_replication_controller') + @mock.patch.object(k8s_utils, 'create_replication_controller') def test_create_rc(self, mock_create_replication_controller): self.k8s_context._create_rc({}) mock_create_replication_controller.assert_called_once() @@ -148,22 +178,96 @@ class KubernetesTestCase(unittest.TestCase): self.k8s_context._delete_rcs() mock_delete_rc.assert_called() - @mock.patch.object(kubernetes.k8s_utils, 'delete_replication_controller') + @mock.patch.object(k8s_utils, 'delete_replication_controller') def test_delete_rc(self, mock_delete_replication_controller): self.k8s_context._delete_rc({}) mock_delete_replication_controller.assert_called_once() - @mock.patch.object(kubernetes.k8s_utils, 'get_node_list') + @mock.patch.object(k8s_utils, 'get_node_list') def test_get_node_ip(self, mock_get_node_list): self.k8s_context._get_node_ip() mock_get_node_list.assert_called_once() - @mock.patch('yardstick.orchestrator.kubernetes.ServiceObject.create') + @mock.patch.object(orchestrator_kubernetes.ServiceNodePortObject, 'create') def test_create_services(self, mock_create): self.k8s_context._create_services() mock_create.assert_called() - @mock.patch('yardstick.orchestrator.kubernetes.ServiceObject.delete') + @mock.patch.object(orchestrator_kubernetes.ServiceNodePortObject, 'delete') def test_delete_services(self, mock_delete): self.k8s_context._delete_services() mock_delete.assert_called() + + def test_init(self): + self.k8s_context._delete_context() + with mock.patch.object(orchestrator_kubernetes, 'KubernetesTemplate', + return_value='fake_template') as mock_k8stemplate: + self.k8s_context = kubernetes.KubernetesContext() + self.k8s_context.init(CONTEXT_CFG) + mock_k8stemplate.assert_called_once_with(self.k8s_context.name, + CONTEXT_CFG) + self.assertEqual('fake_template', self.k8s_context.template) + self.assertEqual(2, len(self.k8s_context._networks)) + self.assertIn('flannel', self.k8s_context._networks.keys()) + self.assertIn('sriov01', self.k8s_context._networks.keys()) + + def test__get_physical_nodes(self): + result = self.k8s_context._get_physical_nodes() + self.assertIsNone(result) + + def test__get_physical_node_for_server(self): + result = self.k8s_context._get_physical_node_for_server("fake") + self.assertIsNone(result) + + def test__get_network(self): + networks = collections.OrderedDict([('n1', 'data1'), ('n2', 'data2')]) + self.k8s_context._networks = networks + self.assertEqual({'name': 'n1'}, self.k8s_context._get_network('n1')) + self.assertEqual({'name': 'n2'}, self.k8s_context._get_network('n2')) + self.assertIsNone(self.k8s_context._get_network('n3')) + + @mock.patch.object(orchestrator_kubernetes.KubernetesTemplate, + 'get_rc_by_name') + def test__get_interfaces(self, mock_get_rc): + rc = orchestrator_kubernetes.ReplicationControllerObject('rc_name') + rc._networks = ['net1', 'net2'] + mock_get_rc.return_value = rc + expected = {'net1': {'network_name': 'net1', + 'local_mac': None, + 'local_ip': None}, + 'net2': {'network_name': 'net2', + 'local_mac': None, + 'local_ip': None}} + self.assertEqual(expected, self.k8s_context._get_interfaces('rc_name')) + + @mock.patch.object(orchestrator_kubernetes.KubernetesTemplate, + 'get_rc_by_name') + def test__get_interfaces_no_networks(self, mock_get_rc): + rc = orchestrator_kubernetes.ReplicationControllerObject('rc_name') + mock_get_rc.return_value = rc + self.assertEqual({}, self.k8s_context._get_interfaces('rc_name')) + + @mock.patch.object(orchestrator_kubernetes.KubernetesTemplate, + 'get_rc_by_name', return_value=None) + def test__get_interfaces_no_rc(self, *args): + self.assertEqual({}, self.k8s_context._get_interfaces('rc_name')) + + @mock.patch.object(k8s_utils, 'get_service_by_name', + return_value=Service()) + def test__get_service_ports(self, mock_get_service_by_name): + name = 'rc_name' + service_ports = self.k8s_context._get_service_ports(name) + mock_get_service_by_name.assert_called_once_with(name + '-service') + expected = {'node_port': 30000, + 'port': constants.SSH_PORT, + 'name': 'port_name', + 'protocol': 'TCP', + 'target_port': constants.SSH_PORT} + self.assertEqual(expected, service_ports[0]) + + @mock.patch.object(k8s_utils, 'get_service_by_name', + return_value=None) + def test__get_service_ports_exception(self, *args): + name = 'rc_name' + with self.assertRaises(exceptions.KubernetesServiceObjectNotDefined): + self.k8s_context._get_service_ports(name) diff --git a/yardstick/tests/unit/benchmark/contexts/test_node.py b/yardstick/tests/unit/benchmark/contexts/test_node.py index 8b232481b..da16074d9 100644 --- a/yardstick/tests/unit/benchmark/contexts/test_node.py +++ b/yardstick/tests/unit/benchmark/contexts/test_node.py @@ -8,12 +8,16 @@ ############################################################################## import os -import unittest import errno + import mock +import unittest -from yardstick.common import constants as consts +from yardstick.benchmark.contexts import base from yardstick.benchmark.contexts import node +from yardstick.common import constants as consts +from yardstick.common import exceptions +from yardstick.common import yaml_loader class NodeContextTestCase(unittest.TestCase): @@ -33,9 +37,11 @@ class NodeContextTestCase(unittest.TestCase): 'file': self._get_file_abspath(self.NODES_SAMPLE) } - def _remove_contexts(self): - if self.test_context in self.test_context.list: - self.test_context._delete_context() + @staticmethod + def _remove_contexts(): + for context in base.Context.list: + context._delete_context() + base.Context.list = [] def _get_file_abspath(self, filename): curr_path = os.path.dirname(os.path.abspath(__file__)) @@ -52,8 +58,9 @@ class NodeContextTestCase(unittest.TestCase): self.assertEqual(self.test_context.env, {}) self.assertEqual(self.test_context.attrs, {}) + @mock.patch.object(yaml_loader, 'read_yaml_file') @mock.patch('{}.os.path.join'.format(PREFIX)) - def test_init_negative(self, mock_path_join): + def test_init_negative(self, mock_path_join, read_mock): special_path = '/foo/bar/error_file' error_path = self._get_file_abspath("error_file") @@ -65,7 +72,6 @@ class NodeContextTestCase(unittest.TestCase): # we can't count mock_path_join calls because # it can catch join calls for .pyc files. mock_path_join.side_effect = path_join - self.test_context.read_config_file = read_mock = mock.Mock() read_calls = 0 with self.assertRaises(KeyError): @@ -83,7 +89,7 @@ class NodeContextTestCase(unittest.TestCase): self.test_context.init(attrs) read_calls += 1 - self.assertEqual(read_mock.called, read_calls) + self.assertEqual(read_mock.call_count, read_calls) self.assertIn(attrs['file'], self.test_context.file_path) self.assertEqual(raised.exception.errno, errno.EBUSY) self.assertEqual(str(raised.exception), str(read_mock.side_effect)) @@ -98,11 +104,6 @@ class NodeContextTestCase(unittest.TestCase): self.assertEqual(raised.exception.errno, errno.ENOENT) self.assertEqual(str(raised.exception), str(read_mock.side_effect)) - def test_read_config_file(self): - self.test_context.init(self.attrs) - - self.assertIsNotNone(self.test_context.read_config_file()) - def test__dispatch_script(self): self.test_context.init(self.attrs) @@ -168,6 +169,39 @@ class NodeContextTestCase(unittest.TestCase): self.assertEqual(result['user'], 'root') self.assertEqual(result['key_filename'], '/root/.yardstick_key') + def test__get_physical_nodes(self): + self.test_context.init(self.attrs) + nodes = self.test_context._get_physical_nodes() + self.assertEqual(nodes, self.test_context.nodes) + + def test__get_physical_node_for_server(self): + self.test_context.init(self.attrs) + + # When server is not from this context + result = self.test_context._get_physical_node_for_server('node1.another-context') + self.assertIsNone(result) + + # When node_name is not from this context + result = self.test_context._get_physical_node_for_server('fake.foo-12345678') + self.assertIsNone(result) + + result = self.test_context._get_physical_node_for_server('node1.foo-12345678') + self.assertEqual(result, 'node1.foo') + + def test_update_collectd_options_for_node(self): + self.test_context.init(self.attrs) + options = {'collectd': {'interval': 5}} + + with self.assertRaises(exceptions.ContextUpdateCollectdForNodeError): + self.test_context.update_collectd_options_for_node(options, 'fake.foo-12345678') + + self.test_context.update_collectd_options_for_node(options, 'node1.foo-12345678') + + node_collectd_options = [node for node in self.test_context.nodes + if node['name'] == 'node1'][0]['collectd'] + + self.assertEqual(node_collectd_options, options) + @mock.patch('{}.NodeContext._dispatch_script'.format(PREFIX)) def test_deploy(self, dispatch_script_mock): obj = node.NodeContext() diff --git a/yardstick/tests/unit/benchmark/core/test_plugin.py b/yardstick/tests/unit/benchmark/core/test_plugin.py index 0d14e4e86..53621316b 100644 --- a/yardstick/tests/unit/benchmark/core/test_plugin.py +++ b/yardstick/tests/unit/benchmark/core/test_plugin.py @@ -12,6 +12,7 @@ import os import pkg_resources import mock +import six import testtools from yardstick import ssh @@ -48,13 +49,17 @@ deployment: self.mock_ssh_from_node.return_value = self.mock_ssh_obj self.mock_ssh_obj.wait = mock.Mock() self.mock_ssh_obj._put_file_shell = mock.Mock() + self._mock_log_info = mock.patch.object(plugin.LOG, 'info') + self.mock_log_info = self._mock_log_info.start() self.addCleanup(self._cleanup) def _cleanup(self): self._mock_ssh_from_node.stop() + self._mock_log_info.stop() - def test_install(self): + @mock.patch.object(six.moves.builtins, 'print') + def test_install(self, *args): args = mock.Mock() args.input_file = [mock.Mock()] with mock.patch.object(self.plugin, '_install_setup') as \ @@ -65,7 +70,8 @@ deployment: PluginTestCase.DEPLOYMENT) mock_run.assert_called_once_with(PluginTestCase.NAME) - def test_remove(self): + @mock.patch.object(six.moves.builtins, 'print') + def test_remove(self, *args): args = mock.Mock() args.input_file = [mock.Mock()] with mock.patch.object(self.plugin, '_remove_setup') as \ diff --git a/yardstick/tests/unit/benchmark/core/test_report.py b/yardstick/tests/unit/benchmark/core/test_report.py index a684ad750..524302f92 100644 --- a/yardstick/tests/unit/benchmark/core/test_report.py +++ b/yardstick/tests/unit/benchmark/core/test_report.py @@ -42,16 +42,16 @@ class ReportTestCase(unittest.TestCase): self.param.task_id = [FAKE_TASK_ID] self.rep = report.Report() - @mock.patch('yardstick.benchmark.core.report.Report._get_tasks') - @mock.patch('yardstick.benchmark.core.report.Report._get_fieldkeys') - @mock.patch('yardstick.benchmark.core.report.Report._validate') + @mock.patch.object(report.Report, '_get_tasks') + @mock.patch.object(report.Report, '_get_fieldkeys') + @mock.patch.object(report.Report, '_validate') def test_generate_success(self, mock_valid, mock_keys, mock_tasks): mock_tasks.return_value = FAKE_DB_TASK mock_keys.return_value = FAKE_DB_FIELDKEYS self.rep.generate(self.param) mock_valid.assert_called_once_with(FAKE_YAML_NAME, FAKE_TASK_ID) - self.assertEqual(1, mock_tasks.call_count) - self.assertEqual(1, mock_keys.call_count) + mock_tasks.assert_called_once_with() + mock_keys.assert_called_once_with() # pylint: disable=deprecated-method def test_invalid_yaml_name(self): diff --git a/yardstick/tests/unit/benchmark/core/test_task.py b/yardstick/tests/unit/benchmark/core/test_task.py index 9e8e4e9f7..e1414c2ae 100644 --- a/yardstick/tests/unit/benchmark/core/test_task.py +++ b/yardstick/tests/unit/benchmark/core/test_task.py @@ -9,14 +9,17 @@ import copy import io +import logging import os import sys import mock import six +from six.moves import builtins import unittest import uuid +from yardstick.benchmark.contexts import base from yardstick.benchmark.contexts import dummy from yardstick.benchmark.core import task from yardstick.common import constants as consts @@ -27,7 +30,7 @@ from yardstick.common import utils class TaskTestCase(unittest.TestCase): - @mock.patch.object(task, 'Context') + @mock.patch.object(base, 'Context') def test_parse_nodes_with_context_same_context(self, mock_context): scenario_cfg = { "nodes": { @@ -68,7 +71,7 @@ class TaskTestCase(unittest.TestCase): dispatcher2]) self.assertIsNone(t._do_output(output_config, {})) - @mock.patch.object(task, 'Context') + @mock.patch.object(base, 'Context') def test_parse_networks_from_nodes(self, mock_context): nodes = { 'node1': { @@ -132,7 +135,7 @@ class TaskTestCase(unittest.TestCase): self.assertEqual(mock_context.get_network.call_count, expected_get_network_calls) self.assertDictEqual(networks, expected) - @mock.patch.object(task, 'Context') + @mock.patch.object(base, 'Context') @mock.patch.object(task, 'base_runner') def test_run(self, mock_base_runner, *args): scenario = { @@ -155,6 +158,31 @@ class TaskTestCase(unittest.TestCase): t._run([scenario], False, "yardstick.out") runner.run.assert_called_once() + @mock.patch.object(base, 'Context') + @mock.patch.object(task, 'base_runner') + def test_run_ProxDuration(self, mock_base_runner, *args): + scenario = { + 'host': 'athena.demo', + 'target': 'ares.demo', + 'runner': { + 'duration': 60, + 'interval': 1, + 'sampled': 'yes', + 'confirmation': 1, + 'type': 'ProxDuration' + }, + 'type': 'Ping' + } + + t = task.Task() + runner = mock.Mock() + runner.join.return_value = 0 + runner.get_output.return_value = {} + runner.get_result.return_value = [] + mock_base_runner.Runner.get.return_value = runner + t._run([scenario], False, "yardstick.out") + runner.run.assert_called_once() + @mock.patch.object(os, 'environ') def test_check_precondition(self, mock_os_environ): cfg = { @@ -296,9 +324,9 @@ class TaskTestCase(unittest.TestCase): actual_result = t._parse_options(options) self.assertEqual(expected_result, actual_result) - @mock.patch('six.moves.builtins.open', side_effect=mock.mock_open()) + @mock.patch.object(builtins, 'open', side_effect=mock.mock_open()) @mock.patch.object(task, 'utils') - @mock.patch('logging.root') + @mock.patch.object(logging, 'root') def test_set_log(self, mock_logging_root, *args): task_obj = task.Task() task_obj.task_id = 'task_id' @@ -357,6 +385,12 @@ key2: } } + @staticmethod + def _remove_contexts(): + for context in base.Context.list: + context._delete_context() + base.Context.list = [] + def test__change_node_names(self): ctx_attrs = { @@ -371,6 +405,7 @@ key2: } my_context = dummy.DummyContext() + self.addCleanup(self._remove_contexts) my_context.init(ctx_attrs) expected_scenario = { @@ -413,6 +448,7 @@ key2: } my_context = dummy.DummyContext() + self.addCleanup(self._remove_contexts) my_context.init(ctx_attrs) scenario = copy.deepcopy(self.scenario) @@ -428,6 +464,7 @@ key2: } my_context = dummy.DummyContext() + self.addCleanup(self._remove_contexts) my_context.init(ctx_attrs) scenario = copy.deepcopy(self.scenario) scenario['options'] = None @@ -442,6 +479,7 @@ key2: } my_context = dummy.DummyContext() + self.addCleanup(self._remove_contexts) my_context.init(ctx_attrs) scenario = copy.deepcopy(self.scenario) scenario['options']['server_name'] = None @@ -525,7 +563,8 @@ key2: mock_open.assert_has_calls([mock.call('args_file'), mock.call('task_file')]) - def test__render_task_error_arguments(self): + @mock.patch.object(builtins, 'print') + def test__render_task_error_arguments(self, *args): with self.assertRaises(exceptions.TaskRenderArgumentError): task.TaskParser('task_file')._render_task('value1="var3"', None) diff --git a/yardstick/tests/unit/benchmark/core/test_testcase.py b/yardstick/tests/unit/benchmark/core/test_testcase.py index 119465887..077848d77 100644 --- a/yardstick/tests/unit/benchmark/core/test_testcase.py +++ b/yardstick/tests/unit/benchmark/core/test_testcase.py @@ -7,28 +7,28 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -# Unittest for yardstick.cmd.commands.testcase - -from __future__ import absolute_import -import unittest +import mock +from six.moves import builtins from yardstick.benchmark.core import testcase +from yardstick.tests.unit import base as ut_base class Arg(object): def __init__(self): - self.casename = ('opnfv_yardstick_tc001',) + self.casename = ('opnfv_yardstick_tc001', ) -class TestcaseUT(unittest.TestCase): +class TestcaseTestCase(ut_base.BaseUnitTestCase): def test_list_all(self): t = testcase.Testcase() result = t.list_all("") self.assertIsInstance(result, list) - def test_show(self): + @mock.patch.object(builtins, 'print') + def test_show(self, *args): t = testcase.Testcase() casename = Arg() result = t.show(casename) diff --git a/yardstick/tests/unit/benchmark/runner/test_arithmetic.py b/yardstick/tests/unit/benchmark/runner/test_arithmetic.py new file mode 100644 index 000000000..7b1e1e976 --- /dev/null +++ b/yardstick/tests/unit/benchmark/runner/test_arithmetic.py @@ -0,0 +1,220 @@ +############################################################################## +# Copyright (c) 2018 Nokia 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 mock +import unittest +import multiprocessing +import os +import time + +from yardstick.benchmark.runners import arithmetic + + +class ArithmeticRunnerTest(unittest.TestCase): + class MyMethod(object): + def __init__(self): + self.count = 101 + + def __call__(self, data): + self.count += 1 + data['my_key'] = self.count + return self.count + + def setUp(self): + self.scenario_cfg = { + 'runner': { + 'interval': 0, + 'iter_type': 'nested_for_loops', + 'iterators': [ + { + 'name': 'stride', + 'start': 64, + 'stop': 128, + 'step': 64 + }, + { + 'name': 'size', + 'start': 500, + 'stop': 2000, + 'step': 500 + } + ] + }, + 'type': 'some_type' + } + + self.benchmark = mock.Mock() + self.benchmark_cls = mock.Mock(return_value=self.benchmark) + + def _assert_defaults__worker_process_run_setup_and_teardown(self): + self.benchmark_cls.assert_called_once_with(self.scenario_cfg, {}) + self.benchmark.setup.assert_called_once() + self.benchmark.teardown.assert_called_once() + + @mock.patch.object(os, 'getpid') + @mock.patch.object(multiprocessing, 'Process') + def test__run_benchmark_called_with(self, mock_multiprocessing_process, + mock_os_getpid): + mock_os_getpid.return_value = 101 + + runner = arithmetic.ArithmeticRunner({}) + benchmark_cls = mock.Mock() + runner._run_benchmark(benchmark_cls, 'my_method', self.scenario_cfg, + {}) + mock_multiprocessing_process.assert_called_once_with( + name='Arithmetic-some_type-101', + target=arithmetic._worker_process, + args=(runner.result_queue, benchmark_cls, 'my_method', + self.scenario_cfg, {}, runner.aborted, runner.output_queue)) + + @mock.patch.object(os, 'getpid') + def test__worker_process_runner_id(self, mock_os_getpid): + mock_os_getpid.return_value = 101 + + arithmetic._worker_process(mock.Mock(), self.benchmark_cls, + 'my_method', self.scenario_cfg, {}, + multiprocessing.Event(), mock.Mock()) + + self.assertEqual(self.scenario_cfg['runner']['runner_id'], 101) + + @mock.patch.object(time, 'sleep') + def test__worker_process_calls_nested_for_loops(self, mock_time_sleep): + self.scenario_cfg['runner']['interval'] = 99 + + arithmetic._worker_process(mock.Mock(), self.benchmark_cls, + 'my_method', self.scenario_cfg, {}, + multiprocessing.Event(), mock.Mock()) + + self._assert_defaults__worker_process_run_setup_and_teardown() + self.benchmark.my_method.assert_has_calls([mock.call({})] * 8) + self.assertEqual(self.benchmark.my_method.call_count, 8) + mock_time_sleep.assert_has_calls([mock.call(99)] * 8) + self.assertEqual(mock_time_sleep.call_count, 8) + + @mock.patch.object(time, 'sleep') + def test__worker_process_calls_tuple_loops(self, mock_time_sleep): + self.scenario_cfg['runner']['interval'] = 99 + self.scenario_cfg['runner']['iter_type'] = 'tuple_loops' + + arithmetic._worker_process(mock.Mock(), self.benchmark_cls, + 'my_method', self.scenario_cfg, {}, + multiprocessing.Event(), mock.Mock()) + + self._assert_defaults__worker_process_run_setup_and_teardown() + self.benchmark.my_method.assert_has_calls([mock.call({})] * 2) + self.assertEqual(self.benchmark.my_method.call_count, 2) + mock_time_sleep.assert_has_calls([mock.call(99)] * 2) + self.assertEqual(mock_time_sleep.call_count, 2) + + def test__worker_process_stored_options_nested_for_loops(self): + arithmetic._worker_process(mock.Mock(), self.benchmark_cls, + 'my_method', self.scenario_cfg, {}, + multiprocessing.Event(), mock.Mock()) + + self.assertDictEqual(self.scenario_cfg['options'], + {'stride': 128, 'size': 2000}) + + def test__worker_process_stored_options_tuple_loops(self): + self.scenario_cfg['runner']['iter_type'] = 'tuple_loops' + + arithmetic._worker_process(mock.Mock(), self.benchmark_cls, + 'my_method', self.scenario_cfg, {}, + multiprocessing.Event(), mock.Mock()) + + self.assertDictEqual(self.scenario_cfg['options'], + {'stride': 128, 'size': 1000}) + + def test__worker_process_aborted_set_early(self): + aborted = multiprocessing.Event() + aborted.set() + arithmetic._worker_process(mock.Mock(), self.benchmark_cls, + 'my_method', self.scenario_cfg, {}, + aborted, mock.Mock()) + + self._assert_defaults__worker_process_run_setup_and_teardown() + self.assertEqual(self.scenario_cfg['options'], {}) + self.benchmark.my_method.assert_not_called() + + def test__worker_process_output_queue_nested_for_loops(self): + self.benchmark.my_method = self.MyMethod() + + output_queue = multiprocessing.Queue() + arithmetic._worker_process(mock.Mock(), self.benchmark_cls, + 'my_method', self.scenario_cfg, {}, + multiprocessing.Event(), output_queue) + time.sleep(0.01) + + self._assert_defaults__worker_process_run_setup_and_teardown() + self.assertEqual(self.benchmark.my_method.count, 109) + result = [] + while not output_queue.empty(): + result.append(output_queue.get()) + self.assertListEqual(result, [102, 103, 104, 105, 106, 107, 108, 109]) + + def test__worker_process_output_queue_tuple_loops(self): + self.scenario_cfg['runner']['iter_type'] = 'tuple_loops' + self.benchmark.my_method = self.MyMethod() + + output_queue = multiprocessing.Queue() + arithmetic._worker_process(mock.Mock(), self.benchmark_cls, + 'my_method', self.scenario_cfg, {}, + multiprocessing.Event(), output_queue) + time.sleep(0.01) + + self._assert_defaults__worker_process_run_setup_and_teardown() + self.assertEqual(self.benchmark.my_method.count, 103) + result = [] + while not output_queue.empty(): + result.append(output_queue.get()) + self.assertListEqual(result, [102, 103]) + + def test__worker_process_queue_nested_for_loops(self): + self.benchmark.my_method = self.MyMethod() + + queue = multiprocessing.Queue() + timestamp = time.time() + arithmetic._worker_process(queue, self.benchmark_cls, 'my_method', + self.scenario_cfg, {}, + multiprocessing.Event(), mock.Mock()) + time.sleep(0.01) + + self._assert_defaults__worker_process_run_setup_and_teardown() + self.assertEqual(self.benchmark.my_method.count, 109) + count = 0 + while not queue.empty(): + count += 1 + result = queue.get() + self.assertEqual(result['errors'], '') + self.assertEqual(result['data'], {'my_key': count + 101}) + self.assertEqual(result['sequence'], count) + self.assertGreater(result['timestamp'], timestamp) + timestamp = result['timestamp'] + + def test__worker_process_queue_tuple_loops(self): + self.scenario_cfg['runner']['iter_type'] = 'tuple_loops' + self.benchmark.my_method = self.MyMethod() + + queue = multiprocessing.Queue() + timestamp = time.time() + arithmetic._worker_process(queue, self.benchmark_cls, 'my_method', + self.scenario_cfg, {}, + multiprocessing.Event(), mock.Mock()) + time.sleep(0.01) + + self._assert_defaults__worker_process_run_setup_and_teardown() + self.assertEqual(self.benchmark.my_method.count, 103) + count = 0 + while not queue.empty(): + count += 1 + result = queue.get() + self.assertEqual(result['errors'], '') + self.assertEqual(result['data'], {'my_key': count + 101}) + self.assertEqual(result['sequence'], count) + self.assertGreater(result['timestamp'], timestamp) + timestamp = result['timestamp'] diff --git a/yardstick/tests/unit/benchmark/runner/test_base.py b/yardstick/tests/unit/benchmark/runner/test_base.py index 727207f5a..49ba1efe4 100644 --- a/yardstick/tests/unit/benchmark/runner/test_base.py +++ b/yardstick/tests/unit/benchmark/runner/test_base.py @@ -8,38 +8,47 @@ ############################################################################## import time +import uuid import mock -import unittest -from subprocess import CalledProcessError +from oslo_config import cfg +import oslo_messaging +import subprocess - -from yardstick.benchmark.runners import base +from yardstick.benchmark.runners import base as runner_base from yardstick.benchmark.runners import iteration +from yardstick.common import messaging +from yardstick.common.messaging import payloads +from yardstick.tests.unit import base as ut_base -class ActionTestCase(unittest.TestCase): +class ActionTestCase(ut_base.BaseUnitTestCase): - @mock.patch("yardstick.benchmark.runners.base.subprocess") - def test__execute_shell_command(self, mock_subprocess): - mock_subprocess.check_output.side_effect = CalledProcessError(-1, '') + def setUp(self): + self._mock_log = mock.patch.object(runner_base.log, 'error') + self.mock_log = self._mock_log.start() + self.addCleanup(self._stop_mocks) - self.assertEqual(base._execute_shell_command("")[0], -1) + def _stop_mocks(self): + self._mock_log.stop() - @mock.patch("yardstick.benchmark.runners.base.subprocess") - def test__single_action(self, mock_subprocess): - mock_subprocess.check_output.side_effect = CalledProcessError(-1, '') + @mock.patch.object(subprocess, 'check_output') + def test__execute_shell_command(self, mock_subprocess): + mock_subprocess.side_effect = subprocess.CalledProcessError(-1, '') + self.assertEqual(runner_base._execute_shell_command("")[0], -1) - base._single_action(0, "echo", mock.MagicMock()) + @mock.patch.object(subprocess, 'check_output') + def test__single_action(self, mock_subprocess): + mock_subprocess.side_effect = subprocess.CalledProcessError(-1, '') + runner_base._single_action(0, 'echo', mock.Mock()) - @mock.patch("yardstick.benchmark.runners.base.subprocess") + @mock.patch.object(subprocess, 'check_output') def test__periodic_action(self, mock_subprocess): - mock_subprocess.check_output.side_effect = CalledProcessError(-1, '') - - base._periodic_action(0, "echo", mock.MagicMock()) + mock_subprocess.side_effect = subprocess.CalledProcessError(-1, '') + runner_base._periodic_action(0, 'echo', mock.Mock()) -class RunnerTestCase(unittest.TestCase): +class RunnerTestCase(ut_base.BaseUnitTestCase): def setUp(self): config = { @@ -86,7 +95,58 @@ class RunnerTestCase(unittest.TestCase): self.assertEqual(idle_result, actual_result) def test__run_benchmark(self): - runner = base.Runner(mock.Mock()) + runner = runner_base.Runner(mock.Mock()) with self.assertRaises(NotImplementedError): runner._run_benchmark(mock.Mock(), mock.Mock(), mock.Mock(), mock.Mock()) + + +class RunnerProducerTestCase(ut_base.BaseUnitTestCase): + + @mock.patch.object(oslo_messaging, 'Target', return_value='rpc_target') + @mock.patch.object(oslo_messaging, 'RPCClient') + @mock.patch.object(oslo_messaging, 'get_rpc_transport', + return_value='rpc_transport') + @mock.patch.object(cfg, 'CONF') + def test__init(self, mock_config, mock_transport, mock_rpcclient, + mock_target): + _id = uuid.uuid1().int + runner_producer = runner_base.RunnerProducer(_id) + mock_transport.assert_called_once_with( + mock_config, url='rabbit://yardstick:yardstick@localhost:5672/') + mock_target.assert_called_once_with(topic=messaging.TOPIC_RUNNER, + fanout=True, + server=messaging.SERVER) + mock_rpcclient.assert_called_once_with('rpc_transport', 'rpc_target') + self.assertEqual(_id, runner_producer._id) + self.assertEqual(messaging.TOPIC_RUNNER, runner_producer._topic) + + @mock.patch.object(oslo_messaging, 'Target', return_value='rpc_target') + @mock.patch.object(oslo_messaging, 'RPCClient') + @mock.patch.object(oslo_messaging, 'get_rpc_transport', + return_value='rpc_transport') + @mock.patch.object(payloads, 'RunnerPayload', return_value='runner_pload') + def test_start_iteration(self, mock_runner_payload, *args): + runner_producer = runner_base.RunnerProducer(uuid.uuid1().int) + with mock.patch.object(runner_producer, + 'send_message') as mock_message: + runner_producer.start_iteration(version=10) + + mock_message.assert_called_once_with( + messaging.RUNNER_METHOD_START_ITERATION, 'runner_pload') + mock_runner_payload.assert_called_once_with(version=10, data={}) + + @mock.patch.object(oslo_messaging, 'Target', return_value='rpc_target') + @mock.patch.object(oslo_messaging, 'RPCClient') + @mock.patch.object(oslo_messaging, 'get_rpc_transport', + return_value='rpc_transport') + @mock.patch.object(payloads, 'RunnerPayload', return_value='runner_pload') + def test_stop_iteration(self, mock_runner_payload, *args): + runner_producer = runner_base.RunnerProducer(uuid.uuid1().int) + with mock.patch.object(runner_producer, + 'send_message') as mock_message: + runner_producer.stop_iteration(version=15) + + mock_message.assert_called_once_with( + messaging.RUNNER_METHOD_STOP_ITERATION, 'runner_pload') + mock_runner_payload.assert_called_once_with(version=15, data={}) diff --git a/yardstick/tests/unit/benchmark/runner/test_duration.py b/yardstick/tests/unit/benchmark/runner/test_duration.py new file mode 100644 index 000000000..21e3874b8 --- /dev/null +++ b/yardstick/tests/unit/benchmark/runner/test_duration.py @@ -0,0 +1,39 @@ +############################################################################## +# Copyright (c) 2018 Nokia 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 mock +import unittest +import multiprocessing +import os + +from yardstick.benchmark.runners import duration + + +class DurationRunnerTest(unittest.TestCase): + def setUp(self): + self.scenario_cfg = { + 'runner': {'interval': 0, "duration": 0}, + 'type': 'some_type' + } + + @mock.patch.object(os, 'getpid') + @mock.patch.object(multiprocessing, 'Process') + def test__run_benchmark_called_with(self, mock_multiprocessing_process, + mock_os_getpid): + mock_os_getpid.return_value = 101 + + runner = duration.DurationRunner({}) + benchmark_cls = mock.Mock() + runner._run_benchmark(benchmark_cls, 'my_method', self.scenario_cfg, + {}) + mock_multiprocessing_process.assert_called_once_with( + name='Duration-some_type-101', + target=duration._worker_process, + args=(runner.result_queue, benchmark_cls, 'my_method', + self.scenario_cfg, {}, runner.aborted, runner.output_queue)) diff --git a/yardstick/tests/unit/benchmark/runner/test_iteration_ipc.py b/yardstick/tests/unit/benchmark/runner/test_iteration_ipc.py new file mode 100644 index 000000000..10d14a8a0 --- /dev/null +++ b/yardstick/tests/unit/benchmark/runner/test_iteration_ipc.py @@ -0,0 +1,136 @@ +# Copyright (c) 2018 Intel Corporation +# +# 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. + +import multiprocessing +import time +import os +import uuid + +import mock + +from yardstick.benchmark.runners import iteration_ipc +from yardstick.common import messaging +from yardstick.common.messaging import payloads +from yardstick.tests.unit import base as ut_base + + +class RunnerIterationIPCEndpointTestCase(ut_base.BaseUnitTestCase): + + def setUp(self): + self._id = uuid.uuid1().int + self._ctx_ids = [uuid.uuid1().int, uuid.uuid1().int] + self._queue = multiprocessing.Queue() + self.runner = iteration_ipc.RunnerIterationIPCEndpoint( + self._id, self._ctx_ids, self._queue) + self._kwargs = {'version': 1, 'iteration': 10, 'kpi': {}} + self._pload_dict = payloads.TrafficGeneratorPayload.dict_to_obj( + self._kwargs).obj_to_dict() + + def test_tg_method_started(self): + self._queue.empty() + ctxt = {'id': self._ctx_ids[0]} + self.runner.tg_method_started(ctxt, **self._kwargs) + time.sleep(0.2) + + output = [] + while not self._queue.empty(): + output.append(self._queue.get(True, 1)) + + self.assertEqual(1, len(output)) + self.assertEqual(self._ctx_ids[0], output[0]['id']) + self.assertEqual(messaging.TG_METHOD_STARTED, output[0]['action']) + self.assertEqual(self._pload_dict, output[0]['payload'].obj_to_dict()) + + def test_tg_method_finished(self): + self._queue.empty() + ctxt = {'id': self._ctx_ids[0]} + self.runner.tg_method_finished(ctxt, **self._kwargs) + time.sleep(0.2) + + output = [] + while not self._queue.empty(): + output.append(self._queue.get(True, 1)) + + self.assertEqual(1, len(output)) + self.assertEqual(self._ctx_ids[0], output[0]['id']) + self.assertEqual(messaging.TG_METHOD_FINISHED, output[0]['action']) + self.assertEqual(self._pload_dict, output[0]['payload'].obj_to_dict()) + + def test_tg_method_iteration(self): + self._queue.empty() + ctxt = {'id': self._ctx_ids[0]} + self.runner.tg_method_iteration(ctxt, **self._kwargs) + time.sleep(0.2) + + output = [] + while not self._queue.empty(): + output.append(self._queue.get(True, 1)) + + self.assertEqual(1, len(output)) + self.assertEqual(self._ctx_ids[0], output[0]['id']) + self.assertEqual(messaging.TG_METHOD_ITERATION, output[0]['action']) + self.assertEqual(self._pload_dict, output[0]['payload'].obj_to_dict()) + + +class RunnerIterationIPCConsumerTestCase(ut_base.BaseUnitTestCase): + + def setUp(self): + self._id = uuid.uuid1().int + self._ctx_ids = [uuid.uuid1().int, uuid.uuid1().int] + self.consumer = iteration_ipc.RunnerIterationIPCConsumer( + self._id, self._ctx_ids) + self.consumer._queue = mock.Mock() + + def test__init(self): + self.assertEqual({self._ctx_ids[0]: [], self._ctx_ids[1]: []}, + self.consumer._kpi_per_id) + + def test_is_all_kpis_received_in_iteration(self): + payload = payloads.TrafficGeneratorPayload( + version=1, iteration=1, kpi={}) + msg1 = {'action': messaging.TG_METHOD_ITERATION, + 'id': self._ctx_ids[0], 'payload': payload} + msg2 = {'action': messaging.TG_METHOD_ITERATION, + 'id': self._ctx_ids[1], 'payload': payload} + self.consumer.iteration_index = 1 + + self.consumer._queue.empty.side_effect = [False, True] + self.consumer._queue.get.return_value = msg1 + self.assertFalse(self.consumer.is_all_kpis_received_in_iteration()) + + self.consumer._queue.empty.side_effect = [False, True] + self.consumer._queue.get.return_value = msg2 + self.assertTrue(self.consumer.is_all_kpis_received_in_iteration()) + + +class IterationIPCRunnerTestCase(ut_base.BaseUnitTestCase): + + @mock.patch.object(iteration_ipc, '_worker_process') + @mock.patch.object(os, 'getpid', return_value=12345678) + @mock.patch.object(multiprocessing, 'Process', return_value=mock.Mock()) + def test__run_benchmark(self, mock_process, mock_getpid, mock_worker): + method = 'method' + scenario_cfg = {'type': 'scenario_type'} + context_cfg = 'context_cfg' + name = '%s-%s-%s' % ('IterationIPC', 'scenario_type', 12345678) + runner = iteration_ipc.IterationIPCRunner(mock.ANY) + mock_getpid.reset_mock() + + runner._run_benchmark('class', method, scenario_cfg, context_cfg) + mock_process.assert_called_once_with( + name=name, + target=mock_worker, + args=(runner.result_queue, 'class', method, scenario_cfg, + context_cfg, runner.aborted, runner.output_queue)) + mock_getpid.assert_called_once() diff --git a/yardstick/tests/unit/benchmark/runner/test_proxduration.py b/yardstick/tests/unit/benchmark/runner/test_proxduration.py new file mode 100644 index 000000000..3299c5b05 --- /dev/null +++ b/yardstick/tests/unit/benchmark/runner/test_proxduration.py @@ -0,0 +1,286 @@ +# Copyright (c) 2018 Intel Corporation +# +# 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. + +import mock +import unittest +import multiprocessing +import os + +from yardstick.benchmark.runners import proxduration +from yardstick.common import constants +from yardstick.common import exceptions as y_exc + + +class ProxDurationRunnerTest(unittest.TestCase): + + class MyMethod(object): + SLA_VALIDATION_ERROR_SIDE_EFFECT = 1 + BROAD_EXCEPTION_SIDE_EFFECT = 2 + + def __init__(self, side_effect=0): + self.count = 101 + self.side_effect = side_effect + + def __call__(self, data): + self.count += 1 + data['my_key'] = self.count + if self.side_effect == self.SLA_VALIDATION_ERROR_SIDE_EFFECT: + raise y_exc.SLAValidationError(case_name='My Case', + error_msg='my error message') + elif self.side_effect == self.BROAD_EXCEPTION_SIDE_EFFECT: + raise y_exc.YardstickException + return self.count + + def setUp(self): + self.scenario_cfg = { + 'runner': {'interval': 0, "duration": 0}, + 'type': 'some_type' + } + + self.benchmark = mock.Mock() + self.benchmark_cls = mock.Mock(return_value=self.benchmark) + + def _assert_defaults__worker_run_setup_and_teardown(self): + self.benchmark_cls.assert_called_once_with(self.scenario_cfg, {}) + self.benchmark.setup.assert_called_once() + self.benchmark.teardown.assert_called_once() + + @mock.patch.object(os, 'getpid') + @mock.patch.object(multiprocessing, 'Process') + def test__run_benchmark_called_with(self, mock_multiprocessing_process, + mock_os_getpid): + mock_os_getpid.return_value = 101 + + runner = proxduration.ProxDurationRunner({}) + benchmark_cls = mock.Mock() + runner._run_benchmark(benchmark_cls, 'my_method', self.scenario_cfg, + {}) + mock_multiprocessing_process.assert_called_once_with( + name='ProxDuration-some_type-101', + target=proxduration._worker_process, + args=(runner.result_queue, benchmark_cls, 'my_method', + self.scenario_cfg, {}, runner.aborted, runner.output_queue)) + + @mock.patch.object(os, 'getpid') + def test__worker_process_runner_id(self, mock_os_getpid): + mock_os_getpid.return_value = 101 + self.scenario_cfg["runner"] = {"sampled": True, "duration": 0.1} + proxduration._worker_process( + mock.Mock(), self.benchmark_cls, 'my_method', self.scenario_cfg, + {}, multiprocessing.Event(), mock.Mock()) + + self.assertEqual(101, self.scenario_cfg['runner']['runner_id']) + + def test__worker_process_called_with_cfg(self): + self.scenario_cfg["runner"] = {"sampled": True, "duration": 0.1} + proxduration._worker_process( + mock.Mock(), self.benchmark_cls, 'my_method', self.scenario_cfg, + {}, multiprocessing.Event(), mock.Mock()) + + self._assert_defaults__worker_run_setup_and_teardown() + + def test__worker_process_called_with_cfg_loop(self): + self.scenario_cfg["runner"] = {"sampled": True, "duration": 0.1} + proxduration._worker_process( + mock.Mock(), self.benchmark_cls, 'my_method', self.scenario_cfg, + {}, multiprocessing.Event(), mock.Mock()) + + self._assert_defaults__worker_run_setup_and_teardown() + self.assertGreater(self.benchmark.my_method.call_count, 2) + + def test__worker_process_called_without_cfg(self): + scenario_cfg = {'runner': {}} + aborted = multiprocessing.Event() + aborted.set() + proxduration._worker_process( + mock.Mock(), self.benchmark_cls, 'my_method', scenario_cfg, {}, + aborted, mock.Mock()) + + self.benchmark_cls.assert_called_once_with(scenario_cfg, {}) + self.benchmark.setup.assert_called_once() + self.benchmark.teardown.assert_called_once() + + def test__worker_process_output_queue(self): + self.benchmark.my_method = mock.Mock(return_value='my_result') + self.scenario_cfg["runner"] = {"sampled": True, "duration": 0.1} + output_queue = mock.Mock() + proxduration._worker_process( + mock.Mock(), self.benchmark_cls, 'my_method', self.scenario_cfg, + {}, multiprocessing.Event(), output_queue) + + self._assert_defaults__worker_run_setup_and_teardown() + output_queue.put.assert_has_calls( + [mock.call('my_result', True, constants.QUEUE_PUT_TIMEOUT)]) + + def test__worker_process_output_queue_multiple_iterations(self): + self.scenario_cfg["runner"] = {"sampled": True, "duration": 0.1} + self.benchmark.my_method = self.MyMethod() + output_queue = mock.Mock() + proxduration._worker_process( + mock.Mock(), self.benchmark_cls, 'my_method', self.scenario_cfg, + {}, multiprocessing.Event(), output_queue) + + self._assert_defaults__worker_run_setup_and_teardown() + for idx in range(102, 101 + len(output_queue.method_calls)): + output_queue.put.assert_has_calls( + [mock.call(idx, True, constants.QUEUE_PUT_TIMEOUT)]) + + def test__worker_process_queue(self): + self.benchmark.my_method = self.MyMethod() + self.scenario_cfg["runner"] = {"sampled": True, "duration": 0.1} + queue = mock.Mock() + proxduration._worker_process( + queue, self.benchmark_cls, 'my_method', self.scenario_cfg, {}, + multiprocessing.Event(), mock.Mock()) + + self._assert_defaults__worker_run_setup_and_teardown() + benchmark_output = {'timestamp': mock.ANY, + 'sequence': 1, + 'data': {'my_key': 102}, + 'errors': ''} + queue.put.assert_has_calls( + [mock.call(benchmark_output, True, constants.QUEUE_PUT_TIMEOUT)]) + + def test__worker_process_queue_multiple_iterations(self): + self.scenario_cfg["runner"] = {"sampled": True, "duration": 0.1} + self.benchmark.my_method = self.MyMethod() + queue = mock.Mock() + proxduration._worker_process( + queue, self.benchmark_cls, 'my_method', self.scenario_cfg, {}, + multiprocessing.Event(), mock.Mock()) + + self._assert_defaults__worker_run_setup_and_teardown() + for idx in range(102, 101 + len(queue.method_calls)): + benchmark_output = {'timestamp': mock.ANY, + 'sequence': idx - 101, + 'data': {'my_key': idx}, + 'errors': ''} + queue.put.assert_has_calls( + [mock.call(benchmark_output, True, + constants.QUEUE_PUT_TIMEOUT)]) + + def test__worker_process_except_sla_validation_error_no_sla_cfg(self): + self.benchmark.my_method = mock.Mock( + side_effect=y_exc.SLAValidationError) + self.scenario_cfg["runner"] = {"sampled": True, "duration": 0.1} + proxduration._worker_process( + mock.Mock(), self.benchmark_cls, 'my_method', self.scenario_cfg, + {}, multiprocessing.Event(), mock.Mock()) + + self._assert_defaults__worker_run_setup_and_teardown() + + @mock.patch.object(proxduration.LOG, 'warning') + def test__worker_process_except_sla_validation_error_sla_cfg_monitor( + self, *args): + self.scenario_cfg['sla'] = {'action': 'monitor'} + self.scenario_cfg["runner"] = {"sampled": True, "duration": 0.1} + self.benchmark.my_method = mock.Mock( + side_effect=y_exc.SLAValidationError) + proxduration._worker_process( + mock.Mock(), self.benchmark_cls, 'my_method', self.scenario_cfg, + {}, multiprocessing.Event(), mock.Mock()) + + self._assert_defaults__worker_run_setup_and_teardown() + + def test__worker_process_raise_sla_validation_error_sla_cfg_default(self): + self.scenario_cfg['sla'] = {} + self.scenario_cfg["runner"] = {"sampled": True, "duration": 0.1} + self.benchmark.my_method = mock.Mock( + side_effect=y_exc.SLAValidationError) + with self.assertRaises(y_exc.SLAValidationError): + proxduration._worker_process( + mock.Mock(), self.benchmark_cls, 'my_method', + self.scenario_cfg, {}, multiprocessing.Event(), mock.Mock()) + + self.benchmark_cls.assert_called_once_with(self.scenario_cfg, {}) + self.benchmark.setup.assert_called_once() + self.benchmark.my_method.assert_called_once_with({}) + + def test__worker_process_raise_sla_validation_error_sla_cfg_assert(self): + self.scenario_cfg["runner"] = {"sampled": True, "duration": 0.1} + self.scenario_cfg['sla'] = {'action': 'assert'} + self.benchmark.my_method = mock.Mock( + side_effect=y_exc.SLAValidationError) + + with self.assertRaises(y_exc.SLAValidationError): + proxduration._worker_process( + mock.Mock(), self.benchmark_cls, 'my_method', + self.scenario_cfg, {}, multiprocessing.Event(), mock.Mock()) + + self.benchmark_cls.assert_called_once_with(self.scenario_cfg, {}) + self.benchmark.setup.assert_called_once() + self.benchmark.my_method.assert_called_once_with({}) + + @mock.patch.object(proxduration.LOG, 'warning') + def test__worker_process_queue_on_sla_validation_error_monitor( + self, *args): + self.scenario_cfg['sla'] = {'action': 'monitor'} + self.scenario_cfg["runner"] = {"sampled": True, "duration": 0.1} + self.benchmark.my_method = self.MyMethod( + side_effect=self.MyMethod.SLA_VALIDATION_ERROR_SIDE_EFFECT) + queue = mock.Mock() + proxduration._worker_process( + queue, self.benchmark_cls, 'my_method', self.scenario_cfg, {}, + multiprocessing.Event(), mock.Mock()) + + self._assert_defaults__worker_run_setup_and_teardown() + benchmark_output = {'timestamp': mock.ANY, + 'sequence': 1, + 'data': {'my_key': 102}, + 'errors': ('My Case SLA validation failed. ' + 'Error: my error message', )} + queue.put.assert_has_calls( + [mock.call(benchmark_output, True, constants.QUEUE_PUT_TIMEOUT)]) + + @mock.patch.object(proxduration.LOG, 'exception') + def test__worker_process_broad_exception(self, *args): + self.benchmark.my_method = mock.Mock( + side_effect=y_exc.YardstickException) + self.scenario_cfg["runner"] = {"sampled": True, "duration": 0.1} + proxduration._worker_process( + mock.Mock(), self.benchmark_cls, 'my_method', + self.scenario_cfg, {}, multiprocessing.Event(), mock.Mock()) + + self._assert_defaults__worker_run_setup_and_teardown() + + @mock.patch.object(proxduration.LOG, 'exception') + def test__worker_process_queue_on_broad_exception(self, *args): + self.benchmark.my_method = self.MyMethod( + side_effect=self.MyMethod.BROAD_EXCEPTION_SIDE_EFFECT) + self.scenario_cfg["runner"] = {"sampled": True, "duration": 0.1} + queue = mock.Mock() + proxduration._worker_process( + queue, self.benchmark_cls, 'my_method', self.scenario_cfg, {}, + multiprocessing.Event(), mock.Mock()) + + benchmark_output = {'timestamp': mock.ANY, + 'sequence': 1, + 'data': {'my_key': 102}, + 'errors': mock.ANY} + queue.put.assert_has_calls( + [mock.call(benchmark_output, True, constants.QUEUE_PUT_TIMEOUT)]) + + @mock.patch.object(proxduration.LOG, 'exception') + def test__worker_process_benchmark_teardown_on_broad_exception( + self, *args): + self.benchmark.teardown = mock.Mock( + side_effect=y_exc.YardstickException) + self.scenario_cfg["runner"] = {"sampled": True, "duration": 0.1} + + with self.assertRaises(SystemExit) as raised: + proxduration._worker_process( + mock.Mock(), self.benchmark_cls, 'my_method', + self.scenario_cfg, {}, multiprocessing.Event(), mock.Mock()) + self.assertEqual(1, raised.exception.code) + self._assert_defaults__worker_run_setup_and_teardown() diff --git a/yardstick/tests/unit/benchmark/runner/test_search.py b/yardstick/tests/unit/benchmark/runner/test_search.py index 4e5b4fe77..d5d1b8ded 100644 --- a/yardstick/tests/unit/benchmark/runner/test_search.py +++ b/yardstick/tests/unit/benchmark/runner/test_search.py @@ -19,36 +19,33 @@ import unittest from yardstick.benchmark.runners.search import SearchRunner from yardstick.benchmark.runners.search import SearchRunnerHelper +from yardstick.common import exceptions as y_exc class TestSearchRunnerHelper(unittest.TestCase): def test___call__(self): - cls = mock.MagicMock() - aborted = mock.MagicMock() scenario_cfg = { 'runner': {}, } - benchmark = cls() - method = getattr(benchmark, 'my_method') + benchmark = mock.Mock() + method = getattr(benchmark(), 'my_method') helper = SearchRunnerHelper( - cls, 'my_method', scenario_cfg, {}, aborted) + benchmark, 'my_method', scenario_cfg, {}, mock.Mock()) with helper.get_benchmark_instance(): helper() - self.assertEqual(method.call_count, 1) + method.assert_called_once() def test___call___error(self): - cls = mock.MagicMock() - aborted = mock.MagicMock() scenario_cfg = { 'runner': {}, } helper = SearchRunnerHelper( - cls, 'my_method', scenario_cfg, {}, aborted) + mock.Mock(), 'my_method', scenario_cfg, {}, mock.Mock()) with self.assertRaises(RuntimeError): helper() @@ -56,8 +53,6 @@ class TestSearchRunnerHelper(unittest.TestCase): @mock.patch.object(time, 'sleep') @mock.patch.object(time, 'time') def test_is_not_done(self, mock_time, *args): - cls = mock.MagicMock() - aborted = mock.MagicMock() scenario_cfg = { 'runner': {}, } @@ -65,7 +60,7 @@ class TestSearchRunnerHelper(unittest.TestCase): mock_time.side_effect = range(1000) helper = SearchRunnerHelper( - cls, 'my_method', scenario_cfg, {}, aborted) + mock.Mock(), 'my_method', scenario_cfg, {}, mock.Mock()) index = -1 for index in helper.is_not_done(): @@ -76,8 +71,6 @@ class TestSearchRunnerHelper(unittest.TestCase): @mock.patch.object(time, 'sleep') def test_is_not_done_immediate_stop(self, *args): - cls = mock.MagicMock() - aborted = mock.MagicMock() scenario_cfg = { 'runner': { 'run_step': '', @@ -85,7 +78,7 @@ class TestSearchRunnerHelper(unittest.TestCase): } helper = SearchRunnerHelper( - cls, 'my_method', scenario_cfg, {}, aborted) + mock.Mock(), 'my_method', scenario_cfg, {}, mock.Mock()) index = -1 for index in helper.is_not_done(): @@ -112,7 +105,7 @@ class TestSearchRunner(unittest.TestCase): } runner = SearchRunner({}) - runner.worker_helper = mock.MagicMock(side_effect=update) + runner.worker_helper = mock.Mock(side_effect=update) self.assertFalse(runner._worker_run_once('sequence 1')) @@ -136,51 +129,49 @@ class TestSearchRunner(unittest.TestCase): } runner = SearchRunner({}) - runner.worker_helper = mock.MagicMock(side_effect=update) + runner.worker_helper = mock.Mock(side_effect=update) self.assertTrue(runner._worker_run_once('sequence 1')) def test__worker_run_once_assertion_error_assert(self): runner = SearchRunner({}) runner.sla_action = 'assert' - runner.worker_helper = mock.MagicMock(side_effect=AssertionError) + runner.worker_helper = mock.Mock(side_effect=y_exc.SLAValidationError) - with self.assertRaises(AssertionError): + with self.assertRaises(y_exc.SLAValidationError): runner._worker_run_once('sequence 1') def test__worker_run_once_assertion_error_monitor(self): runner = SearchRunner({}) runner.sla_action = 'monitor' - runner.worker_helper = mock.MagicMock(side_effect=AssertionError) + runner.worker_helper = mock.Mock(side_effect=y_exc.SLAValidationError) self.assertFalse(runner._worker_run_once('sequence 1')) def test__worker_run_once_non_assertion_error_none(self): runner = SearchRunner({}) - runner.worker_helper = mock.MagicMock(side_effect=RuntimeError) + runner.worker_helper = mock.Mock(side_effect=RuntimeError) self.assertTrue(runner._worker_run_once('sequence 1')) def test__worker_run_once_non_assertion_error(self): runner = SearchRunner({}) runner.sla_action = 'monitor' - runner.worker_helper = mock.MagicMock(side_effect=RuntimeError) + runner.worker_helper = mock.Mock(side_effect=RuntimeError) self.assertFalse(runner._worker_run_once('sequence 1')) def test__worker_run(self): - cls = mock.MagicMock() scenario_cfg = { 'runner': {'interval': 0, 'timeout': 1}, } runner = SearchRunner({}) - runner._worker_run_once = mock.MagicMock(side_effect=[0, 0, 1]) + runner._worker_run_once = mock.Mock(side_effect=[0, 0, 1]) - runner._worker_run(cls, 'my_method', scenario_cfg, {}) + runner._worker_run(mock.Mock(), 'my_method', scenario_cfg, {}) def test__worker_run_immediate_stop(self): - cls = mock.MagicMock() scenario_cfg = { 'runner': { 'run_step': '', @@ -188,15 +179,14 @@ class TestSearchRunner(unittest.TestCase): } runner = SearchRunner({}) - runner._worker_run(cls, 'my_method', scenario_cfg, {}) + runner._worker_run(mock.Mock(), 'my_method', scenario_cfg, {}) @mock.patch('yardstick.benchmark.runners.search.multiprocessing') def test__run_benchmark(self, mock_multi_process): - cls = mock.MagicMock() scenario_cfg = { 'runner': {}, } runner = SearchRunner({}) - runner._run_benchmark(cls, 'my_method', scenario_cfg, {}) - self.assertEqual(mock_multi_process.Process.call_count, 1) + runner._run_benchmark(mock.Mock(), 'my_method', scenario_cfg, {}) + mock_multi_process.Process.assert_called_once() diff --git a/yardstick/tests/unit/benchmark/scenarios/availability/test_attacker_baremetal.py b/yardstick/tests/unit/benchmark/scenarios/availability/test_attacker_baremetal.py index d5c95a086..0f68753fd 100644 --- a/yardstick/tests/unit/benchmark/scenarios/availability/test_attacker_baremetal.py +++ b/yardstick/tests/unit/benchmark/scenarios/availability/test_attacker_baremetal.py @@ -48,7 +48,7 @@ class AttackerBaremetalTestCase(unittest.TestCase): host = { "ipmi_ip": "10.20.0.5", "ipmi_user": "root", - "ipmi_pwd": "123456", + "ipmi_password": "123456", "ip": "10.20.0.5", "user": "root", "key_filename": "/root/.ssh/id_rsa" @@ -77,7 +77,7 @@ class AttackerBaremetalTestCase(unittest.TestCase): def test__attacker_baremetal_recover_successful(self, mock_ssh, mock_subprocess): self.attacker_cfg["jump_host"] = 'node1' - self.context["node1"]["pwd"] = "123456" + self.context["node1"]["password"] = "123456" mock_ssh.SSH.from_node().execute.return_value = (0, "running", '') ins = attacker_baremetal.BaremetalAttacker(self.attacker_cfg, self.context) diff --git a/yardstick/tests/unit/benchmark/scenarios/availability/test_basemonitor.py b/yardstick/tests/unit/benchmark/scenarios/availability/test_basemonitor.py index ce972779d..8d042c406 100644 --- a/yardstick/tests/unit/benchmark/scenarios/availability/test_basemonitor.py +++ b/yardstick/tests/unit/benchmark/scenarios/availability/test_basemonitor.py @@ -7,6 +7,8 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## +import time + import mock import unittest @@ -86,13 +88,19 @@ class BaseMonitorTestCase(unittest.TestCase): 'sla': {'max_outage_time': 5} } + def _close_queue(self, instace): + time.sleep(0.1) + instace._queue.close() + def test__basemonitor_start_wait_successful(self): ins = basemonitor.BaseMonitor(self.monitor_cfg, None, {"nova-api": 10}) + self.addCleanup(self._close_queue, ins) ins.start_monitor() ins.wait_monitor() def test__basemonitor_all_successful(self): ins = self.MonitorSimple(self.monitor_cfg, None, {"nova-api": 10}) + self.addCleanup(self._close_queue, ins) ins.setup() ins.run() ins.verify_SLA() @@ -100,16 +108,12 @@ class BaseMonitorTestCase(unittest.TestCase): @mock.patch.object(basemonitor, 'multiprocessing') def test__basemonitor_func_false(self, mock_multiprocess): ins = self.MonitorSimple(self.monitor_cfg, None, {"nova-api": 10}) + self.addCleanup(self._close_queue, ins) ins.setup() mock_multiprocess.Event().is_set.return_value = False ins.run() ins.verify_SLA() - # TODO(elfoley): fix this test to not throw an error def test__basemonitor_getmonitorcls_successfule(self): - cls = None - try: - cls = basemonitor.BaseMonitor.get_monitor_cls(self.monitor_cfg) - except Exception: # pylint: disable=broad-except - pass - self.assertIsNone(cls) + with self.assertRaises(RuntimeError): + basemonitor.BaseMonitor.get_monitor_cls(self.monitor_cfg) diff --git a/yardstick/tests/unit/benchmark/scenarios/availability/test_scenario_general.py b/yardstick/tests/unit/benchmark/scenarios/availability/test_scenario_general.py index d1172d5a6..dbf3d83b2 100644 --- a/yardstick/tests/unit/benchmark/scenarios/availability/test_scenario_general.py +++ b/yardstick/tests/unit/benchmark/scenarios/availability/test_scenario_general.py @@ -11,6 +11,8 @@ import mock import unittest from yardstick.benchmark.scenarios.availability import scenario_general +from yardstick.common import exceptions as y_exc + class ScenarioGeneralTestCase(unittest.TestCase): @@ -36,19 +38,21 @@ class ScenarioGeneralTestCase(unittest.TestCase): 'index': 2}] } } - self.instance = scenario_general.ScenarioGeneral(self.scenario_cfg, None) + self.instance = scenario_general.ScenarioGeneral(self.scenario_cfg, + None) self.instance.setup() self.instance.director.verify.return_value = True def test_scenario_general_all_successful(self): - ret = {} self.instance.run(ret) self.instance.teardown() self.assertEqual(ret['sla_pass'], 1) - def test_scenario_general_exception(self): - self.instance.director.createActionPlayer.side_effect = KeyError('Wrong') + @mock.patch.object(scenario_general.LOG, 'exception') + def test_scenario_general_exception(self, *args): + self.instance.director.createActionPlayer.side_effect = ( + KeyError('Wrong')) self.instance.director.data = {} ret = {} self.instance.run(ret) @@ -59,6 +63,14 @@ class ScenarioGeneralTestCase(unittest.TestCase): self.instance.director.verify.return_value = False self.instance.director.data = {} ret = {} - self.assertRaises(AssertionError, self.instance.run, ret) + self.assertRaises(y_exc.SLAValidationError, self.instance.run, ret) + self.instance.teardown() + self.assertEqual(ret['sla_pass'], 0) + + def test_scenario_general_case_service_not_found_fail(self): + self.instance.director.verify.return_value = True + self.instance.director.data = {"general-attacker": 0} + ret = {} + self.assertRaises(y_exc.SLAValidationError, self.instance.run, ret) self.instance.teardown() self.assertEqual(ret['sla_pass'], 0) diff --git a/yardstick/tests/unit/benchmark/scenarios/availability/test_serviceha.py b/yardstick/tests/unit/benchmark/scenarios/availability/test_serviceha.py index dd656fbd5..ec0e5973c 100644 --- a/yardstick/tests/unit/benchmark/scenarios/availability/test_serviceha.py +++ b/yardstick/tests/unit/benchmark/scenarios/availability/test_serviceha.py @@ -11,6 +11,7 @@ import mock import unittest from yardstick.benchmark.scenarios.availability import serviceha +from yardstick.common import exceptions as y_exc class ServicehaTestCase(unittest.TestCase): @@ -42,6 +43,13 @@ class ServicehaTestCase(unittest.TestCase): } sla = {"outage_time": 5} self.args = {"options": options, "sla": sla} + self.test__serviceha = serviceha.ServiceHA(self.args, self.ctx) + + def test___init__(self): + + self.assertEqual(self.test__serviceha.data, {}) + self.assertFalse(self.test__serviceha.setup_done) + self.assertFalse(self.test__serviceha.sla_pass) # NOTE(elfoley): This should be split into test_setup and test_run # NOTE(elfoley): This should explicitly test outcomes and states @@ -71,5 +79,36 @@ class ServicehaTestCase(unittest.TestCase): mock_monitor.MonitorMgr().verify_SLA.return_value = False ret = {} - self.assertRaises(AssertionError, p.run, ret) + self.assertRaises(y_exc.SLAValidationError, p.run, ret) + self.assertEqual(ret['sla_pass'], 0) + + @mock.patch.object(serviceha, 'baseattacker') + @mock.patch.object(serviceha, 'basemonitor') + def test__serviceha_run_service_not_found_sla_error(self, mock_monitor, + *args): + p = serviceha.ServiceHA(self.args, self.ctx) + + p.setup() + self.assertTrue(p.setup_done) + p.data["kill-process"] = 0 + + mock_monitor.MonitorMgr().verify_SLA.return_value = True + + ret = {} + self.assertRaises(y_exc.SLAValidationError, p.run, ret) self.assertEqual(ret['sla_pass'], 0) + + @mock.patch.object(serviceha, 'baseattacker') + @mock.patch.object(serviceha, 'basemonitor') + def test__serviceha_no_teardown_when_sla_pass(self, mock_monitor, + *args): + p = serviceha.ServiceHA(self.args, self.ctx) + p.setup() + self.assertTrue(p.setup_done) + mock_monitor.MonitorMgr().verify_SLA.return_value = True + ret = {} + p.run(ret) + attacker = mock.Mock() + p.attackers = [attacker] + p.teardown() + attacker.recover.assert_not_called() diff --git a/yardstick/tests/unit/benchmark/scenarios/compute/test_cyclictest.py b/yardstick/tests/unit/benchmark/scenarios/compute/test_cyclictest.py index f24ec24ec..4fadde4dc 100644 --- a/yardstick/tests/unit/benchmark/scenarios/compute/test_cyclictest.py +++ b/yardstick/tests/unit/benchmark/scenarios/compute/test_cyclictest.py @@ -17,6 +17,7 @@ import mock from oslo_serialization import jsonutils from yardstick.benchmark.scenarios.compute import cyclictest +from yardstick.common import exceptions as y_exc @mock.patch('yardstick.benchmark.scenarios.compute.cyclictest.ssh') @@ -122,7 +123,7 @@ class CyclictestTestCase(unittest.TestCase): sample_output = '{"min": 100, "avg": 500, "max": 1000}' mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '') - self.assertRaises(AssertionError, c.run, result) + self.assertRaises(y_exc.SLAValidationError, c.run, result) def test_cyclictest_unsuccessful_sla_avg_latency(self, mock_ssh): @@ -136,7 +137,7 @@ class CyclictestTestCase(unittest.TestCase): sample_output = '{"min": 100, "avg": 500, "max": 1000}' mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '') - self.assertRaises(AssertionError, c.run, result) + self.assertRaises(y_exc.SLAValidationError, c.run, result) def test_cyclictest_unsuccessful_sla_max_latency(self, mock_ssh): @@ -150,7 +151,7 @@ class CyclictestTestCase(unittest.TestCase): sample_output = '{"min": 100, "avg": 500, "max": 1000}' mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '') - self.assertRaises(AssertionError, c.run, result) + self.assertRaises(y_exc.SLAValidationError, c.run, result) def test_cyclictest_unsuccessful_script_error(self, mock_ssh): diff --git a/yardstick/tests/unit/benchmark/scenarios/compute/test_lmbench.py b/yardstick/tests/unit/benchmark/scenarios/compute/test_lmbench.py index 9640ce000..c4ac347f4 100644 --- a/yardstick/tests/unit/benchmark/scenarios/compute/test_lmbench.py +++ b/yardstick/tests/unit/benchmark/scenarios/compute/test_lmbench.py @@ -17,6 +17,7 @@ import mock from oslo_serialization import jsonutils from yardstick.benchmark.scenarios.compute import lmbench +from yardstick.common import exceptions as y_exc # pylint: disable=unused-argument @@ -144,7 +145,7 @@ class LmbenchTestCase(unittest.TestCase): sample_output = '[{"latency": 37.5, "size": 0.00049}]' mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '') - self.assertRaises(AssertionError, l.run, self.result) + self.assertRaises(y_exc.SLAValidationError, l.run, self.result) def test_unsuccessful_bandwidth_run_sla(self, mock_ssh): @@ -162,7 +163,7 @@ class LmbenchTestCase(unittest.TestCase): sample_output = '{"size(MB)": 0.262144, "bandwidth(MBps)": 9925.5}' mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '') - self.assertRaises(AssertionError, l.run, self.result) + self.assertRaises(y_exc.SLAValidationError, l.run, self.result) def test_successful_latency_for_cache_run_sla(self, mock_ssh): diff --git a/yardstick/tests/unit/benchmark/scenarios/compute/test_qemumigrate.py b/yardstick/tests/unit/benchmark/scenarios/compute/test_qemumigrate.py index 03003d01f..02040ca01 100644 --- a/yardstick/tests/unit/benchmark/scenarios/compute/test_qemumigrate.py +++ b/yardstick/tests/unit/benchmark/scenarios/compute/test_qemumigrate.py @@ -17,6 +17,7 @@ import mock from oslo_serialization import jsonutils from yardstick.benchmark.scenarios.compute import qemu_migrate +from yardstick.common import exceptions as y_exc @mock.patch('yardstick.benchmark.scenarios.compute.qemu_migrate.ssh') @@ -116,7 +117,7 @@ class QemuMigrateTestCase(unittest.TestCase): sample_output = '{"totaltime": 15, "downtime": 2, "setuptime": 1}' mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '') - self.assertRaises(AssertionError, q.run, result) + self.assertRaises(y_exc.SLAValidationError, q.run, result) def test_qemu_migrate_unsuccessful_sla_downtime(self, mock_ssh): @@ -129,7 +130,7 @@ class QemuMigrateTestCase(unittest.TestCase): sample_output = '{"totaltime": 15, "downtime": 2, "setuptime": 1}' mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '') - self.assertRaises(AssertionError, q.run, result) + self.assertRaises(y_exc.SLAValidationError, q.run, result) def test_qemu_migrate_unsuccessful_sla_setuptime(self, mock_ssh): @@ -142,7 +143,7 @@ class QemuMigrateTestCase(unittest.TestCase): sample_output = '{"totaltime": 15, "downtime": 2, "setuptime": 1}' mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '') - self.assertRaises(AssertionError, q.run, result) + self.assertRaises(y_exc.SLAValidationError, q.run, result) def test_qemu_migrate_unsuccessful_script_error(self, mock_ssh): diff --git a/yardstick/tests/unit/benchmark/scenarios/compute/test_ramspeed.py b/yardstick/tests/unit/benchmark/scenarios/compute/test_ramspeed.py index dcc0e810d..9e055befe 100644 --- a/yardstick/tests/unit/benchmark/scenarios/compute/test_ramspeed.py +++ b/yardstick/tests/unit/benchmark/scenarios/compute/test_ramspeed.py @@ -18,6 +18,7 @@ from oslo_serialization import jsonutils from yardstick.common import utils from yardstick.benchmark.scenarios.compute import ramspeed +from yardstick.common import exceptions as y_exc @mock.patch('yardstick.benchmark.scenarios.compute.ramspeed.ssh') @@ -146,7 +147,7 @@ class RamspeedTestCase(unittest.TestCase): "Block_size(kb)": 16384, "Bandwidth(MBps)": 14128.94}, {"Test_type":\ "INTEGER & WRITING", "Block_size(kb)": 32768, "Bandwidth(MBps)": 8340.85}]}' mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '') - self.assertRaises(AssertionError, r.run, self.result) + self.assertRaises(y_exc.SLAValidationError, r.run, self.result) def test_ramspeed_unsuccessful_script_error(self, mock_ssh): options = { @@ -219,7 +220,7 @@ class RamspeedTestCase(unittest.TestCase): "Bandwidth(MBps)": 1300.27}, {"Test_type": "INTEGER AVERAGE:",\ "Bandwidth(MBps)": 2401.58}]}' mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '') - self.assertRaises(AssertionError, r.run, self.result) + self.assertRaises(y_exc.SLAValidationError, r.run, self.result) def test_ramspeed_unsuccessful_unknown_type_run(self, mock_ssh): options = { diff --git a/yardstick/tests/unit/benchmark/scenarios/compute/test_unixbench.py b/yardstick/tests/unit/benchmark/scenarios/compute/test_unixbench.py index 6339a2dcd..e4a8d6e26 100644 --- a/yardstick/tests/unit/benchmark/scenarios/compute/test_unixbench.py +++ b/yardstick/tests/unit/benchmark/scenarios/compute/test_unixbench.py @@ -17,6 +17,7 @@ import mock from oslo_serialization import jsonutils from yardstick.benchmark.scenarios.compute import unixbench +from yardstick.common import exceptions as y_exc @mock.patch('yardstick.benchmark.scenarios.compute.unixbench.ssh') @@ -122,7 +123,7 @@ class UnixbenchTestCase(unittest.TestCase): sample_output = '{"single_score":"200.7","parallel_score":"4395.9"}' mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '') - self.assertRaises(AssertionError, u.run, result) + self.assertRaises(y_exc.SLAValidationError, u.run, result) def test_unixbench_unsuccessful_sla_parallel_score(self, mock_ssh): @@ -137,7 +138,7 @@ class UnixbenchTestCase(unittest.TestCase): sample_output = '{"signle_score":"2251.7","parallel_score":"3395.9"}' mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '') - self.assertRaises(AssertionError, u.run, result) + self.assertRaises(y_exc.SLAValidationError, u.run, result) def test_unixbench_unsuccessful_script_error(self, mock_ssh): diff --git a/yardstick/tests/unit/benchmark/scenarios/lib/test_create_image.py b/yardstick/tests/unit/benchmark/scenarios/lib/test_create_image.py index 639cf2906..aebd1dfe8 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_create_image.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_create_image.py @@ -6,30 +6,50 @@ # which accompanies this distribution, and is available at # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -import unittest + import mock +from oslo_utils import uuidutils +import unittest -from yardstick.benchmark.scenarios.lib import create_image from yardstick.common import openstack_utils +from yardstick.common import exceptions +from yardstick.benchmark.scenarios.lib import create_image + -# NOTE(elfoley): There should be more tests here. class CreateImageTestCase(unittest.TestCase): - @mock.patch.object(openstack_utils, 'create_image') - @mock.patch.object(openstack_utils, 'get_glance_client') - def test_create_image(self, mock_get_glance_client, mock_create_image): - options = { - 'image_name': 'yardstick_test_image_01', - 'disk_format': 'qcow2', - 'container_format': 'bare', - 'min_disk': '1', - 'min_ram': '512', - 'protected': 'False', - 'tags': '["yardstick automatic test image"]', - 'file_path': '/home/opnfv/images/cirros-0.3.5-x86_64-disk.img' - } - args = {"options": options} - obj = create_image.CreateImage(args, {}) - obj.run({}) - mock_create_image.assert_called_once() - mock_get_glance_client.assert_called_once() + def setUp(self): + self._mock_create_image = mock.patch.object( + openstack_utils, 'create_image') + self.mock_create_image = ( + self._mock_create_image.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_image, 'LOG') + self.mock_log = self._mock_log.start() + self.args = {'options': {'image_name': 'yardstick_image'}} + self.result = {} + self.cimage_obj = create_image.CreateImage(self.args, mock.ANY) + self.addCleanup(self._stop_mock) + + def _stop_mock(self): + self._mock_create_image.stop() + self._mock_get_shade_client.stop() + self._mock_log.stop() + + def test_run(self): + _uuid = uuidutils.generate_uuid() + self.cimage_obj.scenario_cfg = {'output': 'id'} + self.mock_create_image.return_value = _uuid + output = self.cimage_obj.run(self.result) + self.assertEqual({'image_create': 1}, self.result) + self.assertEqual({'id': _uuid}, output) + self.mock_log.info.asset_called_once_with('Create image successful!') + + def test_run_fail(self): + self.mock_create_image.return_value = None + with self.assertRaises(exceptions.ScenarioCreateImageError): + self.cimage_obj.run(self.result) + self.assertEqual({'image_create': 0}, self.result) + self.mock_log.error.assert_called_once_with('Create image failed!') 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 e382d46fa..8a1d6d695 100644 --- a/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_image.py +++ b/yardstick/tests/unit/benchmark/scenarios/lib/test_delete_image.py @@ -9,21 +9,44 @@ import unittest import mock -from yardstick.benchmark.scenarios.lib.delete_image import DeleteImage +from yardstick.common import openstack_utils +from yardstick.common import exceptions +from yardstick.benchmark.scenarios.lib import delete_image class DeleteImageTestCase(unittest.TestCase): - @mock.patch('yardstick.common.openstack_utils.delete_image') - @mock.patch('yardstick.common.openstack_utils.get_image_id') - @mock.patch('yardstick.common.openstack_utils.get_glance_client') - def test_delete_image(self, mock_get_glance_client, mock_image_id, mock_delete_image): - options = { - 'image_name': 'yardstick_test_image_01' - } - args = {"options": options} - obj = DeleteImage(args, {}) - obj.run({}) - mock_delete_image.assert_called_once() - mock_image_id.assert_called_once() - mock_get_glance_client.assert_called_once() + def setUp(self): + self._mock_delete_image = mock.patch.object( + openstack_utils, 'delete_image') + self.mock_delete_image = ( + self._mock_delete_image.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_image, 'LOG') + self.mock_log = self._mock_log.start() + self.args = {'options': {'name_or_id': 'yardstick_image'}} + self.result = {} + + self.delimg_obj = delete_image.DeleteImage(self.args, mock.ANY) + + self.addCleanup(self._stop_mock) + + def _stop_mock(self): + self._mock_delete_image.stop() + self._mock_get_shade_client.stop() + self._mock_log.stop() + + def test_run(self): + self.mock_delete_image.return_value = True + self.assertIsNone(self.delimg_obj.run(self.result)) + self.assertEqual({'delete_image': 1}, self.result) + self.mock_log.info.assert_called_once_with('Delete image successful!') + + def test_run_fail(self): + self.mock_delete_image.return_value = False + with self.assertRaises(exceptions.ScenarioDeleteImageError): + self.delimg_obj.run(self.result) + self.assertEqual({'delete_image': 0}, self.result) + self.mock_log.error.assert_called_once_with('Delete image failed!') diff --git a/yardstick/tests/unit/benchmark/scenarios/networking/test_iperf3.py b/yardstick/tests/unit/benchmark/scenarios/networking/test_iperf3.py index 74144afd5..5f342df7d 100644 --- a/yardstick/tests/unit/benchmark/scenarios/networking/test_iperf3.py +++ b/yardstick/tests/unit/benchmark/scenarios/networking/test_iperf3.py @@ -7,10 +7,6 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -# Unittest for yardstick.benchmark.scenarios.networking.iperf3.Iperf - -from __future__ import absolute_import - import os import unittest @@ -19,9 +15,10 @@ from oslo_serialization import jsonutils from yardstick.common import utils from yardstick.benchmark.scenarios.networking import iperf3 +from yardstick.common import exceptions as y_exc -@mock.patch('yardstick.benchmark.scenarios.networking.iperf3.ssh') +@mock.patch.object(iperf3, 'ssh') class IperfTestCase(unittest.TestCase): output_name_tcp = 'iperf3_sample_output.json' output_name_udp = 'iperf3_sample_output_udp.json' @@ -40,9 +37,14 @@ class IperfTestCase(unittest.TestCase): 'ipaddr': '172.16.0.138', } } + self._mock_log_info = mock.patch.object(iperf3.LOG, 'info') + self.mock_log_info = self._mock_log_info.start() + self.addCleanup(self._stop_mocks) - def test_iperf_successful_setup(self, mock_ssh): + def _stop_mocks(self): + self._mock_log_info.stop() + def test_iperf_successful_setup(self, mock_ssh): p = iperf3.Iperf({}, self.ctx) mock_ssh.SSH.from_node().execute.return_value = (0, '', '') @@ -52,13 +54,11 @@ class IperfTestCase(unittest.TestCase): mock_ssh.SSH.from_node().execute.assert_called_with("iperf3 -s -D") def test_iperf_unsuccessful_setup(self, mock_ssh): - p = iperf3.Iperf({}, self.ctx) mock_ssh.SSH.from_node().execute.return_value = (1, '', 'FOOBAR') self.assertRaises(RuntimeError, p.setup) def test_iperf_successful_teardown(self, mock_ssh): - p = iperf3.Iperf({}, self.ctx) mock_ssh.SSH.from_node().execute.return_value = (0, '', '') p.host = mock_ssh.SSH.from_node() @@ -69,7 +69,6 @@ class IperfTestCase(unittest.TestCase): mock_ssh.SSH.from_node().execute.assert_called_with("pkill iperf3") def test_iperf_successful_no_sla(self, mock_ssh): - options = {} args = {'options': options} result = {} @@ -85,7 +84,6 @@ class IperfTestCase(unittest.TestCase): self.assertEqual(result, expected_result) def test_iperf_successful_sla(self, mock_ssh): - options = {} args = { 'options': options, @@ -104,7 +102,6 @@ class IperfTestCase(unittest.TestCase): self.assertEqual(result, expected_result) def test_iperf_unsuccessful_sla(self, mock_ssh): - options = {} args = { 'options': options, @@ -118,7 +115,7 @@ class IperfTestCase(unittest.TestCase): sample_output = self._read_sample_output(self.output_name_tcp) mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '') - self.assertRaises(AssertionError, p.run, result) + self.assertRaises(y_exc.SLAValidationError, p.run, result) def test_iperf_successful_sla_jitter(self, mock_ssh): options = {"protocol": "udp", "bandwidth": "20m"} @@ -152,7 +149,7 @@ class IperfTestCase(unittest.TestCase): sample_output = self._read_sample_output(self.output_name_udp) mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '') - self.assertRaises(AssertionError, p.run, result) + self.assertRaises(y_exc.SLAValidationError, p.run, result) def test_iperf_successful_tcp_protocal(self, mock_ssh): options = {"protocol": "tcp", "nodelay": "yes"} @@ -173,7 +170,6 @@ class IperfTestCase(unittest.TestCase): self.assertEqual(result, expected_result) def test_iperf_unsuccessful_script_error(self, mock_ssh): - options = {} args = {'options': options} result = {} @@ -185,7 +181,8 @@ class IperfTestCase(unittest.TestCase): mock_ssh.SSH.from_node().execute.return_value = (1, '', 'FOOBAR') self.assertRaises(RuntimeError, p.run, result) - def _read_sample_output(self, filename): + @staticmethod + def _read_sample_output(filename): curr_path = os.path.dirname(os.path.abspath(__file__)) output = os.path.join(curr_path, filename) with open(output) as f: diff --git a/yardstick/tests/unit/benchmark/scenarios/networking/test_netperf.py b/yardstick/tests/unit/benchmark/scenarios/networking/test_netperf.py index 5907562c2..a7abcd98a 100755 --- a/yardstick/tests/unit/benchmark/scenarios/networking/test_netperf.py +++ b/yardstick/tests/unit/benchmark/scenarios/networking/test_netperf.py @@ -18,6 +18,7 @@ import mock from oslo_serialization import jsonutils from yardstick.benchmark.scenarios.networking import netperf +from yardstick.common import exceptions as y_exc @mock.patch('yardstick.benchmark.scenarios.networking.netperf.ssh') @@ -98,7 +99,7 @@ class NetperfTestCase(unittest.TestCase): sample_output = self._read_sample_output() mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '') - self.assertRaises(AssertionError, p.run, result) + self.assertRaises(y_exc.SLAValidationError, p.run, result) def test_netperf_unsuccessful_script_error(self, mock_ssh): diff --git a/yardstick/tests/unit/benchmark/scenarios/networking/test_netperf_node.py b/yardstick/tests/unit/benchmark/scenarios/networking/test_netperf_node.py index 956a9c078..a577dba59 100755 --- a/yardstick/tests/unit/benchmark/scenarios/networking/test_netperf_node.py +++ b/yardstick/tests/unit/benchmark/scenarios/networking/test_netperf_node.py @@ -19,6 +19,7 @@ import mock from oslo_serialization import jsonutils from yardstick.benchmark.scenarios.networking import netperf_node +from yardstick.common import exceptions as y_exc @mock.patch('yardstick.benchmark.scenarios.networking.netperf_node.ssh') @@ -98,7 +99,7 @@ class NetperfNodeTestCase(unittest.TestCase): sample_output = self._read_sample_output() mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '') - self.assertRaises(AssertionError, p.run, result) + self.assertRaises(y_exc.SLAValidationError, p.run, result) def test_netperf_node_unsuccessful_script_error(self, mock_ssh): diff --git a/yardstick/tests/unit/benchmark/scenarios/networking/test_ping.py b/yardstick/tests/unit/benchmark/scenarios/networking/test_ping.py index 4adfab120..559e0599e 100644 --- a/yardstick/tests/unit/benchmark/scenarios/networking/test_ping.py +++ b/yardstick/tests/unit/benchmark/scenarios/networking/test_ping.py @@ -14,6 +14,7 @@ import mock import unittest from yardstick.benchmark.scenarios.networking import ping +from yardstick.common import exceptions as y_exc class PingTestCase(unittest.TestCase): @@ -74,7 +75,7 @@ class PingTestCase(unittest.TestCase): p = ping.Ping(args, self.ctx) mock_ssh.SSH.from_node().execute.return_value = (0, '100', '') - self.assertRaises(AssertionError, p.run, result) + self.assertRaises(y_exc.SLAValidationError, p.run, result) @mock.patch('yardstick.benchmark.scenarios.networking.ping.ssh') def test_ping_unsuccessful_script_error(self, mock_ssh): diff --git a/yardstick/tests/unit/benchmark/scenarios/networking/test_ping6.py b/yardstick/tests/unit/benchmark/scenarios/networking/test_ping6.py index 4662c8537..ad5217a14 100644 --- a/yardstick/tests/unit/benchmark/scenarios/networking/test_ping6.py +++ b/yardstick/tests/unit/benchmark/scenarios/networking/test_ping6.py @@ -14,6 +14,7 @@ import mock import unittest from yardstick.benchmark.scenarios.networking import ping6 +from yardstick.common import exceptions as y_exc class PingTestCase(unittest.TestCase): @@ -98,7 +99,7 @@ class PingTestCase(unittest.TestCase): p = ping6.Ping6(args, self.ctx) p.client = mock_ssh.SSH.from_node() mock_ssh.SSH.from_node().execute.side_effect = [(0, 'host1', ''), (0, 100, '')] - self.assertRaises(AssertionError, p.run, result) + self.assertRaises(y_exc.SLAValidationError, p.run, result) @mock.patch('yardstick.benchmark.scenarios.networking.ping6.ssh') def test_ping_unsuccessful_script_error(self, mock_ssh): diff --git a/yardstick/tests/unit/benchmark/scenarios/networking/test_pktgen.py b/yardstick/tests/unit/benchmark/scenarios/networking/test_pktgen.py index 6aea03aee..5761e2403 100644 --- a/yardstick/tests/unit/benchmark/scenarios/networking/test_pktgen.py +++ b/yardstick/tests/unit/benchmark/scenarios/networking/test_pktgen.py @@ -9,17 +9,22 @@ import mock import unittest +import logging from oslo_serialization import jsonutils +from yardstick import ssh from yardstick.benchmark.scenarios.networking import pktgen +from yardstick.common import exceptions as y_exc + + +logging.disable(logging.CRITICAL) -@mock.patch('yardstick.benchmark.scenarios.networking.pktgen.ssh') class PktgenTestCase(unittest.TestCase): def setUp(self): - self.ctx = { + self.context_cfg = { 'host': { 'ip': '172.16.0.137', 'user': 'root', @@ -32,635 +37,416 @@ class PktgenTestCase(unittest.TestCase): 'ipaddr': '172.16.0.138' } } + self.scenario_cfg = { + 'options': {'packetsize': 60} + } - def test_pktgen_successful_setup(self, mock_ssh): + self._mock_SSH = mock.patch.object(ssh, 'SSH') + self.mock_SSH = self._mock_SSH.start() - args = { - 'options': {'packetsize': 60}, - } - p = pktgen.Pktgen(args, self.ctx) - p.setup() + self.mock_SSH.from_node().execute.return_value = (0, '', '') + self.mock_SSH.from_node().run.return_value = 0 - mock_ssh.SSH.from_node().execute.return_value = (0, '', '') - self.assertIsNotNone(p.server) - self.assertIsNotNone(p.client) - self.assertTrue(p.setup_done) + self.addCleanup(self._stop_mock) - def test_pktgen_successful_iptables_setup(self, mock_ssh): + self.scenario = pktgen.Pktgen(self.scenario_cfg, self.context_cfg) + self.scenario.setup() - args = { - 'options': {'packetsize': 60, 'number_of_ports': 10}, - } - p = pktgen.Pktgen(args, self.ctx) - p.server = mock_ssh.SSH.from_node() - p.number_of_ports = args['options']['number_of_ports'] + def _stop_mock(self): + self._mock_SSH.stop() - mock_ssh.SSH.from_node().execute.return_value = (0, '', '') + def test_setup_successful(self): + self.assertIsNotNone(self.scenario.server) + self.assertIsNotNone(self.scenario.client) + self.assertTrue(self.scenario.setup_done) - p._iptables_setup() + def test_iptables_setup_successful(self): + self.scenario.number_of_ports = 10 + self.scenario._iptables_setup() - mock_ssh.SSH.from_node().execute.assert_called_with( + self.mock_SSH.from_node().run.assert_called_with( "sudo iptables -F; " "sudo iptables -A INPUT -p udp --dport 1000:%s -j DROP" % 1010, timeout=60) - def test_pktgen_unsuccessful_iptables_setup(self, mock_ssh): - - args = { - 'options': {'packetsize': 60, 'number_of_ports': 10}, - } - - p = pktgen.Pktgen(args, self.ctx) - p.server = mock_ssh.SSH.from_node() - p.number_of_ports = args['options']['number_of_ports'] + def test_iptables_setup_unsuccessful(self): + self.scenario.number_of_ports = 10 + self.mock_SSH.from_node().run.side_effect = y_exc.SSHError - mock_ssh.SSH.from_node().execute.return_value = (1, '', 'FOOBAR') - self.assertRaises(RuntimeError, p._iptables_setup) + with self.assertRaises(y_exc.SSHError): + self.scenario._iptables_setup() - def test_pktgen_successful_iptables_get_result(self, mock_ssh): + def test_iptables_get_result_successful(self): + self.scenario.number_of_ports = 10 + self.mock_SSH.from_node().execute.return_value = (0, '150000', '') - args = { - 'options': {'packetsize': 60, 'number_of_ports': 10}, - } - - p = pktgen.Pktgen(args, self.ctx) - p.server = mock_ssh.SSH.from_node() - p.number_of_ports = args['options']['number_of_ports'] + result = self.scenario._iptables_get_result() - mock_ssh.SSH.from_node().execute.return_value = (0, '150000', '') - p._iptables_get_result() - - mock_ssh.SSH.from_node().execute.assert_called_with( + self.assertEqual(result, 150000) + self.mock_SSH.from_node().execute.assert_called_with( "sudo iptables -L INPUT -vnx |" "awk '/dpts:1000:%s/ {{printf \"%%s\", $1}}'" - % 1010) - - def test_pktgen_unsuccessful_iptables_get_result(self, mock_ssh): + % 1010, raise_on_error=True) - args = { - 'options': {'packetsize': 60, 'number_of_ports': 10}, - } - - p = pktgen.Pktgen(args, self.ctx) + def test_iptables_get_result_unsuccessful(self): + self.scenario.number_of_ports = 10 + self.mock_SSH.from_node().execute.side_effect = y_exc.SSHError - p.server = mock_ssh.SSH.from_node() - p.number_of_ports = args['options']['number_of_ports'] + with self.assertRaises(y_exc.SSHError): + self.scenario._iptables_get_result() - mock_ssh.SSH.from_node().execute.return_value = (1, '', 'FOOBAR') - self.assertRaises(RuntimeError, p._iptables_get_result) + def test_run_successful_no_sla(self): + self.scenario._iptables_get_result = mock.Mock(return_value=149300) + sample_output = jsonutils.dumps({"packets_per_second": 9753, + "errors": 0, + "packets_sent": 149776, + "packetsize": 60, + "flows": 110, + "ppm": 3179}) + self.mock_SSH.from_node().execute.return_value = (0, sample_output, '') - def test_pktgen_successful_no_sla(self, mock_ssh): - - args = { - 'options': {'packetsize': 60, 'number_of_ports': 10}, - } result = {} + self.scenario.run(result) - p = pktgen.Pktgen(args, self.ctx) - - p.server = mock_ssh.SSH.from_node() - p.client = mock_ssh.SSH.from_node() - - p._iptables_get_result = mock.Mock(return_value=149300) - - sample_output = '{"packets_per_second": 9753, "errors": 0, \ - "packets_sent": 149776, "packetsize": 60, "flows": 110, "ppm": 3179}' - mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '') - - p.run(result) expected_result = jsonutils.loads(sample_output) expected_result["packets_received"] = 149300 expected_result["packetsize"] = 60 self.assertEqual(result, expected_result) - def test_pktgen_successful_sla(self, mock_ssh): + def test_run_successful_sla(self): + self.scenario_cfg['sla'] = {'max_ppm': 10000} + scenario = pktgen.Pktgen(self.scenario_cfg, self.context_cfg) + scenario.setup() + scenario._iptables_get_result = mock.Mock(return_value=149300) + sample_output = jsonutils.dumps({"packets_per_second": 9753, + "errors": 0, + "packets_sent": 149776, + "packetsize": 60, + "flows": 110, + "ppm": 3179}) + self.mock_SSH.from_node().execute.return_value = (0, sample_output, '') - args = { - 'options': {'packetsize': 60, 'number_of_ports': 10}, - 'sla': {'max_ppm': 10000} - } result = {} + scenario.run(result) - p = pktgen.Pktgen(args, self.ctx) - - p.server = mock_ssh.SSH.from_node() - p.client = mock_ssh.SSH.from_node() - - p._iptables_get_result = mock.Mock(return_value=149300) - - sample_output = '{"packets_per_second": 9753, "errors": 0, \ - "packets_sent": 149776, "packetsize": 60, "flows": 110, "ppm": 3179}' - mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '') - - p.run(result) expected_result = jsonutils.loads(sample_output) expected_result["packets_received"] = 149300 expected_result["packetsize"] = 60 self.assertEqual(result, expected_result) - def test_pktgen_unsuccessful_sla(self, mock_ssh): - - args = { - 'options': {'packetsize': 60, 'number_of_ports': 10}, - 'sla': {'max_ppm': 1000} - } - result = {} + def test_run_unsuccessful_sla(self): + self.scenario_cfg['sla'] = {'max_ppm': 1000} + scenario = pktgen.Pktgen(self.scenario_cfg, self.context_cfg) + scenario.setup() + scenario._iptables_get_result = mock.Mock(return_value=149300) + sample_output = jsonutils.dumps({"packets_per_second": 9753, + "errors": 0, + "packets_sent": 149776, + "packetsize": 60, + "flows": 110}) + self.mock_SSH.from_node().execute.return_value = (0, sample_output, '') - p = pktgen.Pktgen(args, self.ctx) + with self.assertRaises(y_exc.SLAValidationError): + scenario.run({}) - p.server = mock_ssh.SSH.from_node() - p.client = mock_ssh.SSH.from_node() + def test_run_ssh_error_not_caught(self): + self.mock_SSH.from_node().execute.side_effect = y_exc.SSHError - p._iptables_get_result = mock.Mock(return_value=149300) + with self.assertRaises(y_exc.SSHError): + self.scenario.run({}) - sample_output = '{"packets_per_second": 9753, "errors": 0, \ - "packets_sent": 149776, "packetsize": 60, "flows": 110}' - mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '') - self.assertRaises(AssertionError, p.run, result) + def test_get_vnic_driver_name(self): + self.mock_SSH.from_node().execute.return_value = (0, 'ixgbevf', '') + vnic_driver_name = self.scenario._get_vnic_driver_name() - def test_pktgen_unsuccessful_script_error(self, mock_ssh): - - args = { - 'options': {'packetsize': 60, 'number_of_ports': 10}, - 'sla': {'max_ppm': 1000} - } - result = {} - - p = pktgen.Pktgen(args, self.ctx) - - p.server = mock_ssh.SSH.from_node() - p.client = mock_ssh.SSH.from_node() - - mock_ssh.SSH.from_node().execute.return_value = (1, '', 'FOOBAR') - self.assertRaises(RuntimeError, p.run, result) - - def test_pktgen_get_vnic_driver_name(self, mock_ssh): - args = { - 'options': {'packetsize': 60}, - } - p = pktgen.Pktgen(args, self.ctx) - p.server = mock_ssh.SSH.from_node() - - mock_ssh.SSH.from_node().execute.return_value = (0, 'ixgbevf', '') - - vnic_driver_name = p._get_vnic_driver_name() self.assertEqual(vnic_driver_name, 'ixgbevf') - def test_pktgen_unsuccessful_get_vnic_driver_name(self, mock_ssh): - args = { - 'options': {'packetsize': 60}, - } - p = pktgen.Pktgen(args, self.ctx) - p.server = mock_ssh.SSH.from_node() + def test_get_vnic_driver_name_unsuccessful(self): + self.mock_SSH.from_node().execute.side_effect = y_exc.SSHError - mock_ssh.SSH.from_node().execute.return_value = (1, '', '') - - self.assertRaises(RuntimeError, p._get_vnic_driver_name) - - def test_pktgen_get_sriov_queue_number(self, mock_ssh): - args = { - 'options': {'packetsize': 60}, - } - p = pktgen.Pktgen(args, self.ctx) - p.server = mock_ssh.SSH.from_node() - - mock_ssh.SSH.from_node().execute.return_value = (0, '2', '') - - p.queue_number = p._get_sriov_queue_number() - self.assertEqual(p.queue_number, 2) - - def test_pktgen_unsuccessful_get_sriov_queue_number(self, mock_ssh): - args = { - 'options': {'packetsize': 60}, - } - p = pktgen.Pktgen(args, self.ctx) - p.server = mock_ssh.SSH.from_node() + with self.assertRaises(y_exc.SSHError): + self.scenario._get_vnic_driver_name() - mock_ssh.SSH.from_node().execute.return_value = (1, '', '') + def test_get_sriov_queue_number(self): + self.mock_SSH.from_node().execute.return_value = (0, '2', '') - self.assertRaises(RuntimeError, p._get_sriov_queue_number) + self.scenario.queue_number = self.scenario._get_sriov_queue_number() + self.assertEqual(self.scenario.queue_number, 2) - def test_pktgen_get_available_queue_number(self, mock_ssh): - args = { - 'options': {'packetsize': 60}, - } - p = pktgen.Pktgen(args, self.ctx) - p.server = mock_ssh.SSH.from_node() + def test_get_sriov_queue_number_unsuccessful(self): + self.mock_SSH.from_node().execute.side_effect = y_exc.SSHError - mock_ssh.SSH.from_node().execute.return_value = (0, '4', '') + with self.assertRaises(y_exc.SSHError): + self.scenario._get_sriov_queue_number() - p._get_available_queue_number() + def test_get_available_queue_number(self): + self.mock_SSH.from_node().execute.return_value = (0, '4', '') - mock_ssh.SSH.from_node().execute.assert_called_with( + self.assertEqual(self.scenario._get_available_queue_number(), 4) + self.mock_SSH.from_node().execute.assert_called_with( "sudo ethtool -l eth0 | grep Combined | head -1 |" - "awk '{printf $2}'") - - def test_pktgen_unsuccessful_get_available_queue_number(self, mock_ssh): - args = { - 'options': {'packetsize': 60}, - } - p = pktgen.Pktgen(args, self.ctx) - p.server = mock_ssh.SSH.from_node() - - mock_ssh.SSH.from_node().execute.return_value = (1, '', '') + "awk '{printf $2}'", raise_on_error=True) - self.assertRaises(RuntimeError, p._get_available_queue_number) + def test_get_available_queue_number_unsuccessful(self): + self.mock_SSH.from_node().execute.side_effect = y_exc.SSHError - def test_pktgen_get_usable_queue_number(self, mock_ssh): - args = { - 'options': {'packetsize': 60}, - } - p = pktgen.Pktgen(args, self.ctx) - p.server = mock_ssh.SSH.from_node() - - mock_ssh.SSH.from_node().execute.return_value = (0, '1', '') + with self.assertRaises(y_exc.SSHError): + self.scenario._get_available_queue_number() - p._get_usable_queue_number() + def test_get_usable_queue_number(self): + self.mock_SSH.from_node().execute.return_value = (0, '1', '') - mock_ssh.SSH.from_node().execute.assert_called_with( + self.assertEqual(self.scenario._get_usable_queue_number(), 1) + self.mock_SSH.from_node().execute.assert_called_with( "sudo ethtool -l eth0 | grep Combined | tail -1 |" - "awk '{printf $2}'") + "awk '{printf $2}'", raise_on_error=True) - def test_pktgen_unsuccessful_get_usable_queue_number(self, mock_ssh): - args = { - 'options': {'packetsize': 60}, - } - p = pktgen.Pktgen(args, self.ctx) - p.server = mock_ssh.SSH.from_node() + def test_get_usable_queue_number_unsuccessful(self): + self.mock_SSH.from_node().execute.side_effect = y_exc.SSHError - mock_ssh.SSH.from_node().execute.return_value = (1, '', '') + with self.assertRaises(y_exc.SSHError): + self.scenario._get_usable_queue_number() - self.assertRaises(RuntimeError, p._get_usable_queue_number) + def test_enable_ovs_multiqueue(self): + self.scenario._get_usable_queue_number = mock.Mock(return_value=1) + self.scenario._get_available_queue_number = mock.Mock(return_value=4) + self.scenario.queue_number = self.scenario._enable_ovs_multiqueue() - def test_pktgen_enable_ovs_multiqueue(self, mock_ssh): - args = { - 'options': {'packetsize': 60}, - } - p = pktgen.Pktgen(args, self.ctx) - p.server = mock_ssh.SSH.from_node() - p.client = mock_ssh.SSH.from_node() + self.assertEqual(self.scenario.queue_number, 4) + self.mock_SSH.from_node().run.assert_has_calls( + (mock.call("sudo ethtool -L eth0 combined 4"), + mock.call("sudo ethtool -L eth0 combined 4"))) - mock_ssh.SSH.from_node().execute.return_value = (0, '4', '') + def test_enable_ovs_multiqueue_1q(self): + self.scenario._get_usable_queue_number = mock.Mock(return_value=1) + self.scenario._get_available_queue_number = mock.Mock(return_value=1) + self.scenario.queue_number = self.scenario._enable_ovs_multiqueue() - p._get_usable_queue_number = mock.Mock(return_value=1) - p._get_available_queue_number = mock.Mock(return_value=4) + self.assertEqual(self.scenario.queue_number, 1) + self.mock_SSH.from_node().run.assert_not_called() - p.queue_number = p._enable_ovs_multiqueue() - self.assertEqual(p.queue_number, 4) - - def test_pktgen_enable_ovs_multiqueue_1q(self, mock_ssh): - args = { - 'options': {'packetsize': 60}, - } - p = pktgen.Pktgen(args, self.ctx) - p.server = mock_ssh.SSH.from_node() - p.client = mock_ssh.SSH.from_node() - - mock_ssh.SSH.from_node().execute.return_value = (0, '1', '') - - p._get_usable_queue_number = mock.Mock(return_value=1) - p._get_available_queue_number = mock.Mock(return_value=1) - - p.queue_number = p._enable_ovs_multiqueue() - self.assertEqual(p.queue_number, 1) - - def test_pktgen_unsuccessful_enable_ovs_multiqueue(self, mock_ssh): - args = { - 'options': {'packetsize': 60}, - } - p = pktgen.Pktgen(args, self.ctx) - p.server = mock_ssh.SSH.from_node() - p.client = mock_ssh.SSH.from_node() + def test_enable_ovs_multiqueue_unsuccessful(self): + self.mock_SSH.from_node().run.side_effect = y_exc.SSHError + self.scenario._get_usable_queue_number = mock.Mock(return_value=1) + self.scenario._get_available_queue_number = mock.Mock(return_value=4) - mock_ssh.SSH.from_node().execute.return_value = (1, '', '') + with self.assertRaises(y_exc.SSHError): + self.scenario._enable_ovs_multiqueue() - p._get_usable_queue_number = mock.Mock(return_value=1) - p._get_available_queue_number = mock.Mock(return_value=4) + def test_setup_irqmapping_ovs(self): + self.mock_SSH.from_node().execute.return_value = (0, '10', '') + self.scenario._setup_irqmapping_ovs(4) - self.assertRaises(RuntimeError, p._enable_ovs_multiqueue) - - def test_pktgen_setup_irqmapping_ovs(self, mock_ssh): - args = { - 'options': {'packetsize': 60}, - } - p = pktgen.Pktgen(args, self.ctx) - p.server = mock_ssh.SSH.from_node() - p.client = mock_ssh.SSH.from_node() - - mock_ssh.SSH.from_node().execute.return_value = (0, '10', '') - - p._setup_irqmapping_ovs(4) - - mock_ssh.SSH.from_node().execute.assert_called_with( + self.mock_SSH.from_node().run.assert_called_with( "echo 8 | sudo tee /proc/irq/10/smp_affinity") - def test_pktgen_setup_irqmapping_ovs_1q(self, mock_ssh): - args = { - 'options': {'packetsize': 60}, - } - p = pktgen.Pktgen(args, self.ctx) - p.server = mock_ssh.SSH.from_node() - p.client = mock_ssh.SSH.from_node() - - mock_ssh.SSH.from_node().execute.return_value = (0, '10', '') - - p._setup_irqmapping_ovs(1) + def test_setup_irqmapping_ovs_1q(self): + self.mock_SSH.from_node().execute.return_value = (0, '10', '') + self.scenario._setup_irqmapping_ovs(1) - mock_ssh.SSH.from_node().execute.assert_called_with( + self.mock_SSH.from_node().run.assert_called_with( "echo 1 | sudo tee /proc/irq/10/smp_affinity") - def test_pktgen_unsuccessful_setup_irqmapping_ovs(self, mock_ssh): - args = { - 'options': {'packetsize': 60}, - } - p = pktgen.Pktgen(args, self.ctx) - p.server = mock_ssh.SSH.from_node() - p.client = mock_ssh.SSH.from_node() - - mock_ssh.SSH.from_node().execute.return_value = (1, '', '') + def test_setup_irqmapping_ovs_unsuccessful(self): + self.mock_SSH.from_node().execute.side_effect = y_exc.SSHError - self.assertRaises(RuntimeError, p._setup_irqmapping_ovs, 4) - - def test_pktgen_unsuccessful_setup_irqmapping_ovs_1q(self, mock_ssh): - args = { - 'options': {'packetsize': 60}, - } - p = pktgen.Pktgen(args, self.ctx) - p.server = mock_ssh.SSH.from_node() - p.client = mock_ssh.SSH.from_node() + with self.assertRaises(y_exc.SSHError): + self.scenario._setup_irqmapping_ovs(4) - mock_ssh.SSH.from_node().execute.return_value = (1, '', '') - - self.assertRaises(RuntimeError, p._setup_irqmapping_ovs, 1) - - def test_pktgen_setup_irqmapping_sriov(self, mock_ssh): - args = { - 'options': {'packetsize': 60}, - } - p = pktgen.Pktgen(args, self.ctx) - p.server = mock_ssh.SSH.from_node() - p.client = mock_ssh.SSH.from_node() + def test_setup_irqmapping_ovs_1q_unsuccessful(self): + self.mock_SSH.from_node().execute.side_effect = y_exc.SSHError - mock_ssh.SSH.from_node().execute.return_value = (0, '10', '') + with self.assertRaises(y_exc.SSHError): + self.scenario._setup_irqmapping_ovs(1) - p._setup_irqmapping_sriov(2) + def test_setup_irqmapping_sriov(self): + self.mock_SSH.from_node().execute.return_value = (0, '10', '') + self.scenario._setup_irqmapping_sriov(2) - mock_ssh.SSH.from_node().execute.assert_called_with( + self.mock_SSH.from_node().run.assert_called_with( "echo 2 | sudo tee /proc/irq/10/smp_affinity") - def test_pktgen_setup_irqmapping_sriov_1q(self, mock_ssh): - args = { - 'options': {'packetsize': 60}, - } - p = pktgen.Pktgen(args, self.ctx) - p.server = mock_ssh.SSH.from_node() - p.client = mock_ssh.SSH.from_node() - - mock_ssh.SSH.from_node().execute.return_value = (0, '10', '') + def test_setup_irqmapping_sriov_1q(self): + self.mock_SSH.from_node().execute.return_value = (0, '10', '') + self.scenario._setup_irqmapping_sriov(1) - p._setup_irqmapping_sriov(1) - - mock_ssh.SSH.from_node().execute.assert_called_with( + self.mock_SSH.from_node().run.assert_called_with( "echo 1 | sudo tee /proc/irq/10/smp_affinity") - def test_pktgen_unsuccessful_setup_irqmapping_sriov(self, mock_ssh): - args = { - 'options': {'packetsize': 60}, - } - p = pktgen.Pktgen(args, self.ctx) - p.server = mock_ssh.SSH.from_node() - p.client = mock_ssh.SSH.from_node() - - mock_ssh.SSH.from_node().execute.return_value = (1, '', '') - - self.assertRaises(RuntimeError, p._setup_irqmapping_sriov, 2) + def test_setup_irqmapping_sriov_unsuccessful(self): + self.mock_SSH.from_node().execute.side_effect = y_exc.SSHError - def test_pktgen_unsuccessful_setup_irqmapping_sriov_1q(self, mock_ssh): - args = { - 'options': {'packetsize': 60}, - } - p = pktgen.Pktgen(args, self.ctx) - p.server = mock_ssh.SSH.from_node() - p.client = mock_ssh.SSH.from_node() + with self.assertRaises(y_exc.SSHError): + self.scenario._setup_irqmapping_sriov(2) - mock_ssh.SSH.from_node().execute.return_value = (1, '', '') + def test_setup_irqmapping_sriov_1q_unsuccessful(self): + self.mock_SSH.from_node().execute.side_effect = y_exc.SSHError - self.assertRaises(RuntimeError, p._setup_irqmapping_sriov, 1) + with self.assertRaises(y_exc.SSHError): + self.scenario._setup_irqmapping_sriov(1) - def test_pktgen_is_irqbalance_disabled(self, mock_ssh): - args = { - 'options': {'packetsize': 60}, - } - p = pktgen.Pktgen(args, self.ctx) - p.server = mock_ssh.SSH.from_node() + def test_is_irqbalance_disabled(self): + self.mock_SSH.from_node().execute.return_value = (0, '', '') - mock_ssh.SSH.from_node().execute.return_value = (0, '', '') + self.assertFalse(self.scenario._is_irqbalance_disabled()) + self.mock_SSH.from_node().execute.assert_called_with( + "grep ENABLED /etc/default/irqbalance", raise_on_error=True) - p._is_irqbalance_disabled() - - mock_ssh.SSH.from_node().execute.assert_called_with( - "grep ENABLED /etc/default/irqbalance") - - def test_pktgen_unsuccessful_is_irqbalance_disabled(self, mock_ssh): - args = { - 'options': {'packetsize': 60}, - } - p = pktgen.Pktgen(args, self.ctx) - p.server = mock_ssh.SSH.from_node() - - mock_ssh.SSH.from_node().execute.return_value = (1, '', '') - - self.assertRaises(RuntimeError, p._is_irqbalance_disabled) - - def test_pktgen_disable_irqbalance(self, mock_ssh): - args = { - 'options': {'packetsize': 60}, - } - p = pktgen.Pktgen(args, self.ctx) - p.server = mock_ssh.SSH.from_node() - p.client = mock_ssh.SSH.from_node() + def test_is_irqbalance_disabled_unsuccessful(self): + self.mock_SSH.from_node().execute.side_effect = y_exc.SSHError - mock_ssh.SSH.from_node().execute.return_value = (0, '', '') + with self.assertRaises(y_exc.SSHError): + self.scenario._is_irqbalance_disabled() - p._disable_irqbalance() + def test_disable_irqbalance(self): + self.scenario._disable_irqbalance() - mock_ssh.SSH.from_node().execute.assert_called_with( + self.mock_SSH.from_node().run.assert_called_with( "sudo service irqbalance disable") - def test_pktgen_unsuccessful_disable_irqbalance(self, mock_ssh): - args = { - 'options': {'packetsize': 60}, - } - p = pktgen.Pktgen(args, self.ctx) - p.server = mock_ssh.SSH.from_node() - p.client = mock_ssh.SSH.from_node() - - mock_ssh.SSH.from_node().execute.return_value = (1, '', '') - - self.assertRaises(RuntimeError, p._disable_irqbalance) - - def test_pktgen_multiqueue_setup_ovs(self, mock_ssh): - args = { - 'options': {'packetsize': 60, 'multiqueue': True}, - } - p = pktgen.Pktgen(args, self.ctx) - p.server = mock_ssh.SSH.from_node() - p.client = mock_ssh.SSH.from_node() - - mock_ssh.SSH.from_node().execute.return_value = (0, '4', '') + def test_disable_irqbalance_unsuccessful(self): + self.mock_SSH.from_node().run.side_effect = y_exc.SSHError - p._is_irqbalance_disabled = mock.Mock(return_value=False) - p._get_vnic_driver_name = mock.Mock(return_value="virtio_net") - p._get_usable_queue_number = mock.Mock(return_value=1) - p._get_available_queue_number = mock.Mock(return_value=4) + with self.assertRaises(y_exc.SSHError): + self.scenario._disable_irqbalance() - p.multiqueue_setup() + def test_multiqueue_setup_ovs(self): + self.mock_SSH.from_node().execute.return_value = (0, '4', '') + self.scenario._is_irqbalance_disabled = mock.Mock(return_value=False) + self.scenario._get_vnic_driver_name = mock.Mock( + return_value="virtio_net") + self.scenario._get_usable_queue_number = mock.Mock(return_value=1) + self.scenario._get_available_queue_number = mock.Mock(return_value=4) - self.assertEqual(p.queue_number, 4) + self.scenario.multiqueue_setup() - def test_pktgen_multiqueue_setup_ovs_1q(self, mock_ssh): - args = { - 'options': {'packetsize': 60, 'multiqueue': True}, - } - p = pktgen.Pktgen(args, self.ctx) - p.server = mock_ssh.SSH.from_node() - p.client = mock_ssh.SSH.from_node() + self.assertEqual(self.scenario.queue_number, 4) + self.assertTrue(self.scenario.multiqueue_setup_done) - mock_ssh.SSH.from_node().execute.return_value = (0, '1', '') + def test_multiqueue_setup_ovs_1q(self): + self.mock_SSH.from_node().execute.return_value = (0, '1', '') + self.scenario._is_irqbalance_disabled = mock.Mock(return_value=False) + self.scenario._get_vnic_driver_name = mock.Mock( + return_value="virtio_net") + self.scenario._get_usable_queue_number = mock.Mock(return_value=1) + self.scenario._get_available_queue_number = mock.Mock(return_value=1) - p._is_irqbalance_disabled = mock.Mock(return_value=False) - p._get_vnic_driver_name = mock.Mock(return_value="virtio_net") - p._get_usable_queue_number = mock.Mock(return_value=1) - p._get_available_queue_number = mock.Mock(return_value=1) + self.scenario.multiqueue_setup() - p.multiqueue_setup() + self.assertEqual(self.scenario.queue_number, 1) + self.assertTrue(self.scenario.multiqueue_setup_done) - self.assertEqual(p.queue_number, 1) + def test_multiqueue_setup_sriov(self): + self.mock_SSH.from_node().execute.return_value = (0, '2', '') + self.scenario._is_irqbalance_disabled = mock.Mock(return_value=False) + self.scenario._get_vnic_driver_name = mock.Mock(return_value="ixgbevf") - def test_pktgen_multiqueue_setup_sriov(self, mock_ssh): - args = { - 'options': {'packetsize': 60, 'multiqueue': True}, - } - p = pktgen.Pktgen(args, self.ctx) - p.server = mock_ssh.SSH.from_node() - p.client = mock_ssh.SSH.from_node() + self.scenario.multiqueue_setup() - mock_ssh.SSH.from_node().execute.return_value = (0, '2', '') + self.assertEqual(self.scenario.queue_number, 2) + self.assertTrue(self.scenario.multiqueue_setup_done) - p._is_irqbalance_disabled = mock.Mock(return_value=False) - p._get_vnic_driver_name = mock.Mock(return_value="ixgbevf") + def test_multiqueue_setup_sriov_1q(self): + self.mock_SSH.from_node().execute.return_value = (0, '1', '') + self.scenario._is_irqbalance_disabled = mock.Mock(return_value=False) + self.scenario._get_vnic_driver_name = mock.Mock(return_value="ixgbevf") - p.multiqueue_setup() + self.scenario.multiqueue_setup() - self.assertEqual(p.queue_number, 2) + self.assertEqual(self.scenario.queue_number, 1) + self.assertTrue(self.scenario.multiqueue_setup_done) - def test_pktgen_multiqueue_setup_sriov_1q(self, mock_ssh): - args = { - 'options': {'packetsize': 60, 'multiqueue': True}, - } - p = pktgen.Pktgen(args, self.ctx) - p.server = mock_ssh.SSH.from_node() - p.client = mock_ssh.SSH.from_node() - - mock_ssh.SSH.from_node().execute.return_value = (0, '1', '') - - p._is_irqbalance_disabled = mock.Mock(return_value=False) - p._get_vnic_driver_name = mock.Mock(return_value="ixgbevf") - - p.multiqueue_setup() - - self.assertEqual(p.queue_number, 1) - - def test_pktgen_run_with_setup_done(self, mock_ssh): - args = { + def test_run_with_setup_done(self): + scenario_cfg = { 'options': { 'packetsize': 60, 'number_of_ports': 10, 'duration': 20, 'multiqueue': True}, 'sla': { - 'max_ppm': 1}} - result = {} - p = pktgen.Pktgen(args, self.ctx) - p.server = mock_ssh.SSH.from_node() - p.client = mock_ssh.SSH.from_node() + 'max_ppm': 1} + } + scenario = pktgen.Pktgen(scenario_cfg, self.context_cfg) + scenario.server = self.mock_SSH.from_node() + scenario.client = self.mock_SSH.from_node() + scenario.setup_done = True + scenario.multiqueue_setup_done = True + scenario._iptables_get_result = mock.Mock(return_value=149300) + + sample_output = jsonutils.dumps({"packets_per_second": 9753, + "errors": 0, + "packets_sent": 149300, + "flows": 110, + "ppm": 0}) + self.mock_SSH.from_node().execute.return_value = (0, sample_output, '') - p.setup_done = True - p.multiqueue_setup_done = True - - mock_iptables_result = mock.Mock() - mock_iptables_result.return_value = 149300 - p._iptables_get_result = mock_iptables_result - - sample_output = '{"packets_per_second": 9753, "errors": 0, \ - "packets_sent": 149300, "flows": 110, "ppm": 0}' - mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '') + result = {} + scenario.run(result) - p.run(result) expected_result = jsonutils.loads(sample_output) expected_result["packets_received"] = 149300 expected_result["packetsize"] = 60 self.assertEqual(result, expected_result) - def test_pktgen_run_with_ovs_multiqueque(self, mock_ssh): - args = { + def test_run_with_ovs_multiqueque(self): + scenario_cfg = { 'options': { 'packetsize': 60, 'number_of_ports': 10, 'duration': 20, 'multiqueue': True}, - 'sla': { - 'max_ppm': 1}} - result = {} - - p = pktgen.Pktgen(args, self.ctx) - - p.server = mock_ssh.SSH.from_node() - p.client = mock_ssh.SSH.from_node() - - p._get_vnic_driver_name = mock.Mock(return_value="virtio_net") - p._get_usable_queue_number = mock.Mock(return_value=1) - p._get_available_queue_number = mock.Mock(return_value=4) - p._enable_ovs_multiqueue = mock.Mock(return_value=4) - p._setup_irqmapping_ovs = mock.Mock() - p._iptables_get_result = mock.Mock(return_value=149300) + 'sla': {'max_ppm': 1} + } + scenario = pktgen.Pktgen(scenario_cfg, self.context_cfg) + scenario.setup() + scenario._get_vnic_driver_name = mock.Mock(return_value="virtio_net") + scenario._get_usable_queue_number = mock.Mock(return_value=1) + scenario._get_available_queue_number = mock.Mock(return_value=4) + scenario._enable_ovs_multiqueue = mock.Mock(return_value=4) + scenario._setup_irqmapping_ovs = mock.Mock() + scenario._iptables_get_result = mock.Mock(return_value=149300) + + sample_output = jsonutils.dumps({"packets_per_second": 9753, + "errors": 0, + "packets_sent": 149300, + "flows": 110, + "ppm": 0}) + self.mock_SSH.from_node().execute.return_value = (0, sample_output, '') - sample_output = '{"packets_per_second": 9753, "errors": 0, \ - "packets_sent": 149300, "flows": 110, "ppm": 0}' - mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '') + result = {} + scenario.run(result) - p.run(result) expected_result = jsonutils.loads(sample_output) expected_result["packets_received"] = 149300 expected_result["packetsize"] = 60 self.assertEqual(result, expected_result) - def test_pktgen_run_with_sriov_multiqueque(self, mock_ssh): - args = { + def test_run_with_sriov_multiqueque(self): + scenario_cfg = { 'options': { 'packetsize': 60, 'number_of_ports': 10, 'duration': 20, 'multiqueue': True}, - 'sla': { - 'max_ppm': 1}} - result = {} - - p = pktgen.Pktgen(args, self.ctx) + 'sla': {'max_ppm': 1} + } + scenario = pktgen.Pktgen(scenario_cfg, self.context_cfg) + scenario.setup() + scenario._get_vnic_driver_name = mock.Mock(return_value="ixgbevf") + scenario._get_sriov_queue_number = mock.Mock(return_value=2) + scenario._setup_irqmapping_sriov = mock.Mock() + scenario._iptables_get_result = mock.Mock(return_value=149300) + + sample_output = jsonutils.dumps({"packets_per_second": 9753, + "errors": 0, + "packets_sent": 149300, + "flows": 110, + "ppm": 0}) + self.mock_SSH.from_node().execute.return_value = (0, sample_output, '') - p.server = mock_ssh.SSH.from_node() - p.client = mock_ssh.SSH.from_node() - - p._get_vnic_driver_name = mock.Mock(return_value="ixgbevf") - p._get_sriov_queue_number = mock.Mock(return_value=2) - p._setup_irqmapping_sriov = mock.Mock() - p._iptables_get_result = mock.Mock(return_value=149300) - - sample_output = '{"packets_per_second": 9753, "errors": 0, \ - "packets_sent": 149300, "flows": 110, "ppm": 0}' - mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '') + result = {} + scenario.run(result) - p.run(result) expected_result = jsonutils.loads(sample_output) expected_result["packets_received"] = 149300 expected_result["packetsize"] = 60 diff --git a/yardstick/tests/unit/benchmark/scenarios/networking/test_pktgen_dpdk.py b/yardstick/tests/unit/benchmark/scenarios/networking/test_pktgen_dpdk.py index 976087148..70cd8ad40 100644 --- a/yardstick/tests/unit/benchmark/scenarios/networking/test_pktgen_dpdk.py +++ b/yardstick/tests/unit/benchmark/scenarios/networking/test_pktgen_dpdk.py @@ -9,15 +9,22 @@ import mock import unittest +import time +import logging import yardstick.common.utils as utils +from yardstick import ssh from yardstick.benchmark.scenarios.networking import pktgen_dpdk +from yardstick.common import exceptions as y_exc + + +logging.disable(logging.CRITICAL) class PktgenDPDKLatencyTestCase(unittest.TestCase): def setUp(self): - self.ctx = { + self.context_cfg = { 'host': { 'ip': '172.16.0.137', 'user': 'root', @@ -30,149 +37,100 @@ class PktgenDPDKLatencyTestCase(unittest.TestCase): 'ipaddr': '172.16.0.138' } } - - self._mock_ssh = mock.patch( - 'yardstick.benchmark.scenarios.networking.pktgen_dpdk.ssh') - self.mock_ssh = self._mock_ssh.start() - self._mock_time = mock.patch( - 'yardstick.benchmark.scenarios.networking.pktgen_dpdk.time') - self.mock_time = self._mock_time.start() - - self.addCleanup(self._stop_mock) - - def _stop_mock(self): - self._mock_ssh.stop() - self._mock_time.stop() - - def test_pktgen_dpdk_successful_setup(self): - - args = { - 'options': {'packetsize': 60}, - } - p = pktgen_dpdk.PktgenDPDKLatency(args, self.ctx) - p.setup() - - self.mock_ssh.SSH.from_node().execute.return_value = (0, '', '') - self.assertIsNotNone(p.server) - self.assertIsNotNone(p.client) - self.assertTrue(p.setup_done) - - def test_pktgen_dpdk_successful_get_port_ip(self): - - args = { - 'options': {'packetsize': 60}, - } - p = pktgen_dpdk.PktgenDPDKLatency(args, self.ctx) - p.server = self.mock_ssh.SSH.from_node() - - self.mock_ssh.SSH.from_node().execute.return_value = (0, '', '') - - utils.get_port_ip(p.server, "eth1") - - self.mock_ssh.SSH.from_node().execute.assert_called_with( - "ifconfig eth1 |grep 'inet addr' |awk '{print $2}' |cut -d ':' -f2 ") - - def test_pktgen_dpdk_unsuccessful_get_port_ip(self): - - args = { - 'options': {'packetsize': 60}, + self.scenario_cfg = { + 'options': {'packetsize': 60} } - p = pktgen_dpdk.PktgenDPDKLatency(args, self.ctx) - p.server = self.mock_ssh.SSH.from_node() + self._mock_SSH = mock.patch.object(ssh, 'SSH') + self.mock_SSH = self._mock_SSH.start() - self.mock_ssh.SSH.from_node().execute.return_value = (1, '', 'FOOBAR') - self.assertRaises(RuntimeError, utils.get_port_ip, p.server, "eth1") + self._mock_time_sleep = mock.patch.object(time, 'sleep') + self.mock_time_sleep = self._mock_time_sleep.start() - def test_pktgen_dpdk_successful_get_port_mac(self): + self._mock_utils_get_port_ip = mock.patch.object(utils, 'get_port_ip') + self.mock_utils_get_port_ip = self._mock_utils_get_port_ip.start() - args = { - 'options': {'packetsize': 60}, - } - p = pktgen_dpdk.PktgenDPDKLatency(args, self.ctx) - p.server = self.mock_ssh.SSH.from_node() + self._mock_utils_get_port_mac = mock.patch.object(utils, + 'get_port_mac') + self.mock_utils_get_port_mac = self._mock_utils_get_port_mac.start() - self.mock_ssh.SSH.from_node().execute.return_value = (0, '', '') + self.mock_SSH.from_node().execute.return_value = (0, '', '') - utils.get_port_mac(p.server, "eth1") + self.addCleanup(self._stop_mock) - self.mock_ssh.SSH.from_node().execute.assert_called_with( - "ifconfig |grep HWaddr |grep eth1 |awk '{print $5}' ") + self.scenario = pktgen_dpdk.PktgenDPDKLatency(self.scenario_cfg, + self.context_cfg) + self.scenario.server = self.mock_SSH.from_node() + self.scenario.client = self.mock_SSH.from_node() - def test_pktgen_dpdk_unsuccessful_get_port_mac(self): + def _stop_mock(self): + self._mock_SSH.stop() + self._mock_time_sleep.stop() + self._mock_utils_get_port_ip.stop() + self._mock_utils_get_port_mac.stop() - args = { - 'options': {'packetsize': 60}, - } + def test_setup(self): + scenario = pktgen_dpdk.PktgenDPDKLatency(self.scenario_cfg, + self.context_cfg) + scenario.setup() - p = pktgen_dpdk.PktgenDPDKLatency(args, self.ctx) - p.server = self.mock_ssh.SSH.from_node() + self.assertIsNotNone(scenario.server) + self.assertIsNotNone(scenario.client) + self.assertTrue(scenario.setup_done) - self.mock_ssh.SSH.from_node().execute.return_value = (1, '', 'FOOBAR') - self.assertRaises(RuntimeError, utils.get_port_mac, p.server, "eth1") + def test_run_get_port_ip_command(self): + self.scenario.run({}) - def test_pktgen_dpdk_successful_no_sla(self): + self.mock_utils_get_port_ip.assert_has_calls( + [mock.call(self.scenario.server, 'ens4'), + mock.call(self.scenario.server, 'ens5')]) - args = { - 'options': {'packetsize': 60}, - } + def test_get_port_mac_command(self): + self.scenario.run({}) - result = {} - p = pktgen_dpdk.PktgenDPDKLatency(args, self.ctx) + self.mock_utils_get_port_mac.assert_has_calls( + [mock.call(self.scenario.server, 'ens5'), + mock.call(self.scenario.server, 'ens4'), + mock.call(self.scenario.server, 'ens5')]) + def test_run_no_sla(self): sample_output = '100\n110\n112\n130\n149\n150\n90\n150\n200\n162\n' - self.mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '') + self.mock_SSH.from_node().execute.return_value = (0, sample_output, '') - p.run(result) + result = {} + self.scenario.run(result) # with python 3 we get float, might be due python division changes # AssertionError: {'avg_latency': 132.33333333333334} != { # 'avg_latency': 132} delta = result['avg_latency'] - 132 self.assertLessEqual(delta, 1) - def test_pktgen_dpdk_successful_sla(self): - - args = { - 'options': {'packetsize': 60}, - 'sla': {'max_latency': 100} - } - result = {} - - p = pktgen_dpdk.PktgenDPDKLatency(args, self.ctx) + def test_run_sla(self): + self.scenario_cfg['sla'] = {'max_latency': 100} + scenario = pktgen_dpdk.PktgenDPDKLatency(self.scenario_cfg, + self.context_cfg) sample_output = '100\n100\n100\n100\n100\n100\n100\n100\n100\n100\n' - self.mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '') + self.mock_SSH.from_node().execute.return_value = (0, sample_output, '') - p.run(result) - - self.assertEqual(result, {"avg_latency": 100}) - - def test_pktgen_dpdk_unsuccessful_sla(self): - - args = { - 'options': {'packetsize': 60}, - 'sla': {'max_latency': 100} - } result = {} + scenario.run(result) - p = pktgen_dpdk.PktgenDPDKLatency(args, self.ctx) + self.assertEqual(result, {"avg_latency": 100}) - p.server = self.mock_ssh.SSH.from_node() - p.client = self.mock_ssh.SSH.from_node() + def test_run_sla_error(self): + self.scenario_cfg['sla'] = {'max_latency': 100} + scenario = pktgen_dpdk.PktgenDPDKLatency(self.scenario_cfg, + self.context_cfg) sample_output = '100\n110\n112\n130\n149\n150\n90\n150\n200\n162\n' - self.mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '') - self.assertRaises(AssertionError, p.run, result) - - def test_pktgen_dpdk_unsuccessful_script_error(self): + self.mock_SSH.from_node().execute.return_value = (0, sample_output, '') - args = { - 'options': {'packetsize': 60}, - 'sla': {'max_latency': 100} - } - result = {} + with self.assertRaises(y_exc.SLAValidationError): + scenario.run({}) - p = pktgen_dpdk.PktgenDPDKLatency(args, self.ctx) + def test_run_last_command_raise_on_error(self): + self.mock_SSH.from_node().execute.side_effect = y_exc.SSHError - self.mock_ssh.SSH.from_node().execute.return_value = (1, '', 'FOOBAR') - self.assertRaises(RuntimeError, p.run, result) + with self.assertRaises(y_exc.SSHError): + self.scenario.run({}) diff --git a/yardstick/tests/unit/benchmark/scenarios/networking/test_pktgen_dpdk_throughput.py b/yardstick/tests/unit/benchmark/scenarios/networking/test_pktgen_dpdk_throughput.py index e90fb07c7..39392e4bb 100644 --- a/yardstick/tests/unit/benchmark/scenarios/networking/test_pktgen_dpdk_throughput.py +++ b/yardstick/tests/unit/benchmark/scenarios/networking/test_pktgen_dpdk_throughput.py @@ -16,6 +16,7 @@ from oslo_serialization import jsonutils import mock from yardstick.benchmark.scenarios.networking import pktgen_dpdk_throughput +from yardstick.common import exceptions as y_exc # pylint: disable=unused-argument @@ -131,7 +132,7 @@ class PktgenDPDKTestCase(unittest.TestCase): sample_output = '{"packets_per_second": 9753, "errors": 0, \ "packets_sent": 149776, "flows": 110}' mock_ssh.SSH().execute.return_value = (0, sample_output, '') - self.assertRaises(AssertionError, p.run, result) + self.assertRaises(y_exc.SLAValidationError, p.run, result) def test_pktgen_dpdk_throughput_unsuccessful_script_error( self, mock_ssh): diff --git a/yardstick/tests/unit/benchmark/scenarios/networking/test_vnf_generic.py b/yardstick/tests/unit/benchmark/scenarios/networking/test_vnf_generic.py index 9bfbf0752..49578b383 100644 --- a/yardstick/tests/unit/benchmark/scenarios/networking/test_vnf_generic.py +++ b/yardstick/tests/unit/benchmark/scenarios/networking/test_vnf_generic.py @@ -20,11 +20,11 @@ import mock import unittest from yardstick import tests +from yardstick.common import exceptions from yardstick.common import utils from yardstick.network_services.collector.subscriber import Collector from yardstick.network_services.traffic_profile import base from yardstick.network_services.vnf_generic import vnfdgen -from yardstick.error import IncorrectConfig from yardstick.network_services.vnf_generic.vnf.base import GenericTrafficGen from yardstick.network_services.vnf_generic.vnf.base import GenericVNF @@ -358,35 +358,49 @@ class TestNetworkServiceTestCase(unittest.TestCase): self.assertIsNotNone(self.topology) def test__get_ip_flow_range_string(self): - self.scenario_cfg["traffic_options"]["flow"] = \ - self._get_file_abspath("ipv4_1flow_Packets_vpe.yaml") result = '152.16.100.2-152.16.100.254' self.assertEqual(result, self.s._get_ip_flow_range( '152.16.100.2-152.16.100.254')) - def test__get_ip_flow_range(self): - self.scenario_cfg["traffic_options"]["flow"] = \ - self._get_file_abspath("ipv4_1flow_Packets_vpe.yaml") - result = '152.16.100.2-152.16.100.254' - self.assertEqual(result, self.s._get_ip_flow_range({"tg__1": 'xe0'})) + def test__get_ip_flow_range_no_nodes(self): + self.assertEqual('0.0.0.0', self.s._get_ip_flow_range({})) - @mock.patch('yardstick.benchmark.scenarios.networking.vnf_generic.ipaddress') - def test__get_ip_flow_range_no_node_data(self, mock_ipaddress): - scenario_cfg = deepcopy(self.scenario_cfg) - scenario_cfg["traffic_options"]["flow"] = \ - self._get_file_abspath("ipv4_1flow_Packets_vpe.yaml") + def test__get_ip_flow_range_no_node_data(self): + node_data = {'tg__0': 'xe0'} + self.s.context_cfg['nodes']['tg__0'] = {} + result = self.s._get_ip_flow_range(node_data) + self.assertEqual('0.0.0.2-0.0.0.254', result) - mock_ipaddress.ip_network.return_value = ipaddr = mock.Mock() - ipaddr.hosts.return_value = [] + def test__et_ip_flow_range_ipv4(self): + node_data = {'tg__0': 'xe0'} + self.s.context_cfg['nodes']['tg__0'] = { + 'interfaces': { + 'xe0': {'local_ip': '192.168.1.15', + 'netmask': '255.255.255.128'} + } + } + result = self.s._get_ip_flow_range(node_data) + self.assertEqual('192.168.1.2-192.168.1.126', result) - expected = '0.0.0.0' - result = self.s._get_ip_flow_range({"tg__2": 'xe0'}) - self.assertEqual(result, expected) + def test__get_ip_flow_range_ipv4_mask_30(self): + node_data = {'tg__0': 'xe0'} + self.s.context_cfg['nodes']['tg__0'] = { + 'interfaces': { + 'xe0': {'local_ip': '192.168.1.15', 'netmask': 30} + } + } + result = self.s._get_ip_flow_range(node_data) + self.assertEqual('192.168.1.15', result) - def test__get_ip_flow_range_no_nodes(self): - expected = '0.0.0.0' - result = self.s._get_ip_flow_range({}) - self.assertEqual(result, expected) + def test__get_ip_flow_range_ipv6(self): + node_data = {'tg__0': 'xe0'} + self.s.context_cfg['nodes']['tg__0'] = { + 'interfaces': { + 'xe0': {'local_ip': '2001::11', 'netmask': 64} + } + } + result = self.s._get_ip_flow_range(node_data) + self.assertEqual('2001::2-2001::ffff:ffff:ffff:fffe', result) def test___get_traffic_flow(self): self.scenario_cfg["traffic_options"]["flow"] = \ @@ -423,7 +437,7 @@ class TestNetworkServiceTestCase(unittest.TestCase): with mock.patch.dict(sys.modules, tests.STL_MOCKS): self.assertIsNotNone(self.s.get_vnf_impl(vnfd)) - with self.assertRaises(vnf_generic.IncorrectConfig) as raised: + with self.assertRaises(exceptions.IncorrectConfig) as raised: self.s.get_vnf_impl('NonExistentClass') exc_str = str(raised.exception) @@ -436,6 +450,7 @@ class TestNetworkServiceTestCase(unittest.TestCase): self._get_file_abspath("tg_trex_tpl.yaml") self.context_cfg["nodes"]['vnf__1']['VNF model'] = \ self._get_file_abspath("tg_trex_tpl.yaml") + self.context_cfg['task_id'] = 'fake_task_id' vnf = mock.Mock(autospec=GenericVNF) self.s.get_vnf_impl = mock.Mock(return_value=vnf) @@ -465,7 +480,7 @@ class TestNetworkServiceTestCase(unittest.TestCase): cfg_patch = mock.patch.object(self.s, 'context_cfg', cfg) with cfg_patch: - with self.assertRaises(IncorrectConfig): + with self.assertRaises(exceptions.IncorrectConfig): self.s.map_topology_to_infrastructure() def test_map_topology_to_infrastructure_config_invalid(self): @@ -482,7 +497,7 @@ class TestNetworkServiceTestCase(unittest.TestCase): config_patch = mock.patch.object(self.s, 'context_cfg', cfg) with config_patch: - with self.assertRaises(IncorrectConfig): + with self.assertRaises(exceptions.IncorrectConfig): self.s.map_topology_to_infrastructure() def test__resolve_topology_invalid_config(self): @@ -496,7 +511,7 @@ class TestNetworkServiceTestCase(unittest.TestCase): for interface in self.tg__1['interfaces'].values(): del interface['local_mac'] - with self.assertRaises(vnf_generic.IncorrectConfig) as raised: + with self.assertRaises(exceptions.IncorrectConfig) as raised: self.s._resolve_topology() self.assertIn('not found', str(raised.exception)) @@ -509,7 +524,7 @@ class TestNetworkServiceTestCase(unittest.TestCase): self.s.topology["vld"][0]['vnfd-connection-point-ref'].append( self.s.topology["vld"][0]['vnfd-connection-point-ref'][0]) - with self.assertRaises(vnf_generic.IncorrectConfig) as raised: + with self.assertRaises(exceptions.IncorrectConfig) as raised: self.s._resolve_topology() self.assertIn('wrong endpoint count', str(raised.exception)) @@ -518,7 +533,7 @@ class TestNetworkServiceTestCase(unittest.TestCase): self.s.topology["vld"][0]['vnfd-connection-point-ref'] = \ self.s.topology["vld"][0]['vnfd-connection-point-ref'][:1] - with self.assertRaises(vnf_generic.IncorrectConfig) as raised: + with self.assertRaises(exceptions.IncorrectConfig) as raised: self.s._resolve_topology() self.assertIn('wrong endpoint count', str(raised.exception)) @@ -553,6 +568,7 @@ class TestNetworkServiceTestCase(unittest.TestCase): tgen.verify_traffic = lambda x: verified_dict tgen.terminate = mock.Mock(return_value=True) tgen.name = "tgen__1" + tgen.run_traffic.return_value = 'tg_id' vnf = mock.Mock(autospec=GenericVNF) vnf.runs_traffic = False vnf.terminate = mock.Mock(return_value=True) @@ -565,7 +581,6 @@ class TestNetworkServiceTestCase(unittest.TestCase): self.s.load_vnf_models = mock.Mock(return_value=self.s.vnfs) self.s._fill_traffic_profile = \ mock.Mock(return_value=TRAFFIC_PROFILE) - self.assertIsNone(self.s.setup()) def test_setup_exception(self): with mock.patch("yardstick.ssh.SSH") as ssh: @@ -628,7 +643,8 @@ class TestNetworkServiceTestCase(unittest.TestCase): 'extra_args': {'arg1': 'value1', 'arg2': 'value2'}, 'flow': {'flow': {}}, 'imix': {'imix': {'64B': 100}}, - 'uplink': {}} + 'uplink': {}, + 'duration': 30} ) mock_tprofile_get.assert_called_once_with(fake_vnfd) @@ -655,6 +671,9 @@ class TestNetworkServiceTestCase(unittest.TestCase): ) self.assertEqual(self.s.topology, 'fake_nsd') + def test_get_mq_ids(self): + self.assertEqual(self.s._mq_ids, self.s.get_mq_ids()) + def test_teardown(self): vnf = mock.Mock(autospec=GenericVNF) vnf.terminate = mock.Mock(return_value=True) diff --git a/yardstick/tests/unit/benchmark/scenarios/networking/test_vsperf.py b/yardstick/tests/unit/benchmark/scenarios/networking/test_vsperf.py index 419605b26..a1c27f5fb 100644 --- a/yardstick/tests/unit/benchmark/scenarios/networking/test_vsperf.py +++ b/yardstick/tests/unit/benchmark/scenarios/networking/test_vsperf.py @@ -12,31 +12,26 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Unittest for yardstick.benchmark.scenarios.networking.vsperf.Vsperf - -from __future__ import absolute_import -try: - from unittest import mock -except ImportError: - import mock +import mock import unittest +import subprocess +import yardstick.ssh as ssh from yardstick.benchmark.scenarios.networking import vsperf +from yardstick import exceptions as y_exc -@mock.patch('yardstick.benchmark.scenarios.networking.vsperf.subprocess') -@mock.patch('yardstick.benchmark.scenarios.networking.vsperf.ssh') class VsperfTestCase(unittest.TestCase): def setUp(self): - self.ctx = { + self.context_cfg = { "host": { "ip": "10.229.47.137", "user": "ubuntu", "password": "ubuntu", }, } - self.args = { + self.scenario_cfg = { 'options': { 'testname': 'p2p_rfc2544_continuous', 'traffic_type': 'continuous', @@ -57,70 +52,145 @@ class VsperfTestCase(unittest.TestCase): } } - def test_vsperf_setup(self, mock_ssh, mock_subprocess): - p = vsperf.Vsperf(self.args, self.ctx) - mock_ssh.SSH.from_node().execute.return_value = (0, '', '') - mock_subprocess.call().execute.return_value = None + self._mock_SSH = mock.patch.object(ssh, 'SSH') + self.mock_SSH = self._mock_SSH.start() + self.mock_SSH.from_node().execute.return_value = ( + 0, 'throughput_rx_fps\r\n14797660.000\r\n', '') - p.setup() - self.assertIsNotNone(p.client) - self.assertTrue(p.setup_done) + self._mock_subprocess_call = mock.patch.object(subprocess, 'call') + self.mock_subprocess_call = self._mock_subprocess_call.start() + self.mock_subprocess_call.return_value = None + + self.addCleanup(self._stop_mock) + + self.scenario = vsperf.Vsperf(self.scenario_cfg, self.context_cfg) + + def _stop_mock(self): + self._mock_SSH.stop() + self._mock_subprocess_call.stop() + + def test_setup(self): + self.scenario.setup() + self.assertIsNotNone(self.scenario.client) + self.assertTrue(self.scenario.setup_done) + + def test_setup_tg_port_not_set(self): + del self.scenario_cfg['options']['trafficgen_port1'] + del self.scenario_cfg['options']['trafficgen_port2'] + scenario = vsperf.Vsperf(self.scenario_cfg, self.context_cfg) + scenario.setup() + + self.mock_subprocess_call.assert_called_once_with( + 'setup_yardstick.sh setup', shell=True) + self.assertIsNone(scenario.tg_port1) + self.assertIsNone(scenario.tg_port2) + self.assertIsNotNone(scenario.client) + self.assertTrue(scenario.setup_done) + + def test_setup_no_setup_script(self): + del self.scenario_cfg['options']['setup_script'] + scenario = vsperf.Vsperf(self.scenario_cfg, self.context_cfg) + scenario.setup() + + self.mock_subprocess_call.assert_has_calls( + (mock.call('sudo bash -c "ovs-vsctl add-port br-ex eth1"', + shell=True), + mock.call('sudo bash -c "ovs-vsctl add-port br-ex eth3"', + shell=True))) + self.assertEqual(2, self.mock_subprocess_call.call_count) + self.assertIsNone(scenario.setup_script) + self.assertIsNotNone(scenario.client) + self.assertTrue(scenario.setup_done) + + def test_run_ok(self): + self.scenario.setup() - def test_vsperf_teardown(self, mock_ssh, mock_subprocess): - p = vsperf.Vsperf(self.args, self.ctx) + result = {} + self.scenario.run(result) - # setup() specific mocks - mock_ssh.SSH.from_node().execute.return_value = (0, '', '') - mock_subprocess.call().execute.return_value = None + self.assertEqual(result['throughput_rx_fps'], '14797660.000') - p.setup() - self.assertIsNotNone(p.client) - self.assertTrue(p.setup_done) + def test_run_ok_setup_not_done(self): + result = {} + self.scenario.run(result) - p.teardown() - self.assertFalse(p.setup_done) + self.assertTrue(self.scenario.setup_done) + self.assertEqual(result['throughput_rx_fps'], '14797660.000') - def test_vsperf_run_ok(self, mock_ssh, mock_subprocess): - p = vsperf.Vsperf(self.args, self.ctx) + def test_run_ssh_command_call_counts(self): + self.scenario.run({}) - # setup() specific mocks - mock_ssh.SSH.from_node().execute.return_value = (0, '', '') - mock_subprocess.call().execute.return_value = None + self.assertEqual(self.mock_SSH.from_node().execute.call_count, 2) + self.mock_SSH.from_node().run.assert_called_once() - # run() specific mocks - mock_ssh.SSH.from_node().execute.return_value = (0, '', '') - mock_ssh.SSH.from_node().execute.return_value = ( - 0, 'throughput_rx_fps\r\n14797660.000\r\n', '') + def test_run_sla_fail(self): + self.mock_SSH.from_node().execute.return_value = ( + 0, 'throughput_rx_fps\r\n123456.000\r\n', '') - result = {} - p.run(result) + with self.assertRaises(y_exc.SLAValidationError) as raised: + self.scenario.run({}) - self.assertEqual(result['throughput_rx_fps'], '14797660.000') + self.assertTrue('VSPERF_throughput_rx_fps(123456.000000) < ' + 'SLA_throughput_rx_fps(500000.000000)' + in str(raised.exception)) - def test_vsperf_run_falied_vsperf_execution(self, mock_ssh, - mock_subprocess): - p = vsperf.Vsperf(self.args, self.ctx) + def test_run_sla_fail_metric_not_collected(self): + self.mock_SSH.from_node().execute.return_value = ( + 0, 'nonexisting_metric\r\n14797660.000\r\n', '') - # setup() specific mocks - mock_ssh.SSH.from_node().execute.return_value = (0, '', '') - mock_subprocess.call().execute.return_value = None + with self.assertRaises(y_exc.SLAValidationError) as raised: + self.scenario.run({}) - # run() specific mocks - mock_ssh.SSH.from_node().execute.return_value = (1, '', '') + self.assertTrue('throughput_rx_fps was not collected by VSPERF' + in str(raised.exception)) - result = {} - self.assertRaises(RuntimeError, p.run, result) + def test_run_faulty_result_csv(self): + self.mock_SSH.from_node().execute.return_value = ( + 0, 'faulty output not csv', '') - def test_vsperf_run_falied_csv_report(self, mock_ssh, mock_subprocess): - p = vsperf.Vsperf(self.args, self.ctx) + with self.assertRaises(y_exc.SLAValidationError) as raised: + self.scenario.run({}) - # setup() specific mocks - mock_ssh.SSH.from_node().execute.return_value = (0, '', '') - mock_subprocess.call().execute.return_value = None + self.assertTrue('throughput_rx_fps was not collected by VSPERF' + in str(raised.exception)) - # run() specific mocks - mock_ssh.SSH.from_node().execute.return_value = (0, '', '') - mock_ssh.SSH.from_node().execute.return_value = (1, '', '') + def test_run_sla_fail_metric_not_defined_in_sla(self): + del self.scenario_cfg['sla']['throughput_rx_fps'] + scenario = vsperf.Vsperf(self.scenario_cfg, self.context_cfg) + scenario.setup() - result = {} - self.assertRaises(RuntimeError, p.run, result) + with self.assertRaises(y_exc.SLAValidationError) as raised: + scenario.run({}) + self.assertTrue('throughput_rx_fps is not defined in SLA' + in str(raised.exception)) + + def test_teardown(self): + self.scenario.setup() + self.assertIsNotNone(self.scenario.client) + self.assertTrue(self.scenario.setup_done) + + self.scenario.teardown() + self.assertFalse(self.scenario.setup_done) + + def test_teardown_tg_port_not_set(self): + del self.scenario_cfg['options']['trafficgen_port1'] + del self.scenario_cfg['options']['trafficgen_port2'] + scenario = vsperf.Vsperf(self.scenario_cfg, self.context_cfg) + scenario.teardown() + + self.mock_subprocess_call.assert_called_once_with( + 'setup_yardstick.sh teardown', shell=True) + self.assertFalse(scenario.setup_done) + + def test_teardown_no_setup_script(self): + del self.scenario_cfg['options']['setup_script'] + scenario = vsperf.Vsperf(self.scenario_cfg, self.context_cfg) + scenario.teardown() + + self.mock_subprocess_call.assert_has_calls( + (mock.call('sudo bash -c "ovs-vsctl del-port br-ex eth1"', + shell=True), + mock.call('sudo bash -c "ovs-vsctl del-port br-ex eth3"', + shell=True))) + self.assertEqual(2, self.mock_subprocess_call.call_count) + self.assertFalse(scenario.setup_done) diff --git a/yardstick/tests/unit/benchmark/scenarios/networking/test_vsperf_dpdk.py b/yardstick/tests/unit/benchmark/scenarios/networking/test_vsperf_dpdk.py index 1d2278e21..8bbe6911e 100644 --- a/yardstick/tests/unit/benchmark/scenarios/networking/test_vsperf_dpdk.py +++ b/yardstick/tests/unit/benchmark/scenarios/networking/test_vsperf_dpdk.py @@ -18,7 +18,10 @@ import time import mock import unittest +from yardstick import exceptions as y_exc from yardstick.benchmark.scenarios.networking import vsperf_dpdk +from yardstick.common import exceptions as y_exc +from yardstick import ssh class VsperfDPDKTestCase(unittest.TestCase): @@ -55,79 +58,51 @@ class VsperfDPDKTestCase(unittest.TestCase): 'action': 'monitor', } } - - self.scenario = vsperf_dpdk.VsperfDPDK(self.args, self.ctx) - - self._mock_ssh = mock.patch( - 'yardstick.benchmark.scenarios.networking.vsperf_dpdk.ssh') + self._mock_ssh = mock.patch.object(ssh, 'SSH') self.mock_ssh = self._mock_ssh.start() self._mock_subprocess_call = mock.patch.object(subprocess, 'call') self.mock_subprocess_call = self._mock_subprocess_call.start() + mock_call_obj = mock.Mock() + mock_call_obj.execute.return_value = None + self.mock_subprocess_call.return_value = mock_call_obj + + self._mock_log_info = mock.patch.object(vsperf_dpdk.LOG, 'info') + self.mock_log_info = self._mock_log_info.start() self.addCleanup(self._cleanup) + self.scenario = vsperf_dpdk.VsperfDPDK(self.args, self.ctx) + self.scenario.setup() + def _cleanup(self): self._mock_ssh.stop() self._mock_subprocess_call.stop() + self._mock_log_info.stop() def test_setup(self): - # setup() specific mocks - self.mock_subprocess_call().execute.return_value = None - - self.scenario.setup() self.assertIsNotNone(self.scenario.client) self.assertTrue(self.scenario.setup_done) def test_teardown(self): - # setup() specific mocks - self.mock_subprocess_call().execute.return_value = None - - self.scenario.setup() - self.assertIsNotNone(self.scenario.client) - self.assertTrue(self.scenario.setup_done) - self.scenario.teardown() self.assertFalse(self.scenario.setup_done) def test_is_dpdk_setup_no(self): - # setup() specific mocks - self.mock_subprocess_call().execute.return_value = None - - self.scenario.setup() - self.assertIsNotNone(self.scenario.client) - self.assertTrue(self.scenario.setup_done) - # is_dpdk_setup() specific mocks - self.mock_ssh.SSH.from_node().execute.return_value = (0, 'dummy', '') + self.mock_ssh.from_node().execute.return_value = (0, 'dummy', '') - result = self.scenario._is_dpdk_setup() - self.assertFalse(result) + self.assertFalse(self.scenario._is_dpdk_setup()) def test_is_dpdk_setup_yes(self): - # setup() specific mocks - self.mock_subprocess_call().execute.return_value = None - - self.scenario.setup() - self.assertIsNotNone(self.scenario.client) - self.assertTrue(self.scenario.setup_done) - # is_dpdk_setup() specific mocks - self.mock_ssh.SSH.from_node().execute.return_value = (0, '', '') + self.mock_ssh.from_node().execute.return_value = (0, '', '') - result = self.scenario._is_dpdk_setup() - self.assertTrue(result) + self.assertTrue(self.scenario._is_dpdk_setup()) @mock.patch.object(time, 'sleep') def test_dpdk_setup_first(self, *args): - # setup() specific mocks - self.mock_subprocess_call().execute.return_value = None - - self.scenario.setup() - self.assertIsNotNone(self.scenario.client) - self.assertTrue(self.scenario.setup_done) - # is_dpdk_setup() specific mocks - self.mock_ssh.SSH.from_node().execute.return_value = (0, 'dummy', '') + self.mock_ssh.from_node().execute.return_value = (0, 'dummy', '') self.scenario.dpdk_setup() self.assertFalse(self.scenario._is_dpdk_setup()) @@ -135,79 +110,72 @@ class VsperfDPDKTestCase(unittest.TestCase): @mock.patch.object(time, 'sleep') def test_dpdk_setup_next(self, *args): - # setup() specific mocks - self.mock_ssh.SSH.from_node().execute.return_value = (0, '', '') - self.mock_subprocess_call().execute.return_value = None - - self.scenario.setup() - self.assertIsNotNone(self.scenario.client) - self.assertTrue(self.scenario.setup_done) + self.mock_ssh.from_node().execute.return_value = (0, '', '') self.scenario.dpdk_setup() self.assertTrue(self.scenario._is_dpdk_setup()) self.assertTrue(self.scenario.dpdk_setup_done) - @mock.patch.object(time, 'sleep') - def test_dpdk_setup_runtime_error(self, *args): - - # setup specific mocks - self.mock_ssh.SSH.from_node().execute.return_value = (0, '', '') - self.mock_subprocess_call().execute.return_value = None - - self.scenario.setup() - self.assertIsNotNone(self.scenario.client) - self.mock_ssh.SSH.from_node().execute.return_value = (1, '', '') - self.assertTrue(self.scenario.setup_done) - - self.assertRaises(RuntimeError, self.scenario.dpdk_setup) - @mock.patch.object(subprocess, 'check_output') - @mock.patch('time.sleep') def test_run_ok(self, *args): - # setup() specific mocks - self.mock_ssh.SSH.from_node().execute.return_value = (0, '', '') - self.mock_subprocess_call().execute.return_value = None - - self.scenario.setup() - self.assertIsNotNone(self.scenario.client) - self.assertTrue(self.scenario.setup_done) - # run() specific mocks - self.mock_subprocess_call().execute.return_value = None - self.mock_ssh.SSH.from_node().execute.return_value = ( + self.mock_ssh.from_node().execute.return_value = ( 0, 'throughput_rx_fps\r\n14797660.000\r\n', '') result = {} self.scenario.run(result) - self.assertEqual(result['throughput_rx_fps'], '14797660.000') - def test_run_failed_vsperf_execution(self): - # setup() specific mocks - self.mock_ssh.SSH.from_node().execute.return_value = (0, '', '') - self.mock_subprocess_call().execute.return_value = None + @mock.patch.object(time, 'sleep') + @mock.patch.object(subprocess, 'check_output') + def test_vsperf_run_sla_fail(self, *args): + self.mock_ssh.from_node().execute.return_value = ( + 0, 'throughput_rx_fps\r\n123456.000\r\n', '') + + with self.assertRaises(y_exc.SLAValidationError) as raised: + self.scenario.run({}) + self.assertIn('VSPERF_throughput_rx_fps(123456.000000) < ' + 'SLA_throughput_rx_fps(500000.000000)', + str(raised.exception)) + + @mock.patch.object(time, 'sleep') + @mock.patch.object(subprocess, 'check_output') + def test_vsperf_run_sla_fail_metric_not_collected(self, *args): + self.mock_ssh.from_node().execute.return_value = ( + 0, 'nonexisting_metric\r\n123456.000\r\n', '') + + with self.assertRaises(y_exc.SLAValidationError) as raised: + self.scenario.run({}) + + self.assertIn('throughput_rx_fps was not collected by VSPERF', + str(raised.exception)) + + @mock.patch.object(time, 'sleep') + @mock.patch.object(subprocess, 'check_output') + def test_vsperf_run_sla_fail_metric_not_collected_faulty_csv(self, *args): self.scenario.setup() - self.assertIsNotNone(self.scenario.client) - self.assertTrue(self.scenario.setup_done) - self.mock_ssh.SSH.from_node().execute.return_value = (1, '', '') + self.mock_ssh.from_node().execute.return_value = ( + 0, 'faulty output not csv', '') - result = {} - self.assertRaises(RuntimeError, self.scenario.run, result) + with self.assertRaises(y_exc.SLAValidationError) as raised: + self.scenario.run({}) - def test_run_falied_csv_report(self): - # setup() specific mocks - self.mock_ssh.SSH.from_node().execute.return_value = (0, '', '') - self.mock_subprocess_call().execute.return_value = None + self.assertIn('throughput_rx_fps was not collected by VSPERF', + str(raised.exception)) + @mock.patch.object(time, 'sleep') + @mock.patch.object(subprocess, 'check_output') + def test_vsperf_run_sla_fail_sla_not_defined(self, *args): + del self.scenario.scenario_cfg['sla']['throughput_rx_fps'] self.scenario.setup() - self.assertIsNotNone(self.scenario.client) - self.assertTrue(self.scenario.setup_done) - # run() specific mocks - self.mock_subprocess_call().execute.return_value = None - self.mock_ssh.SSH.from_node().execute.return_value = (1, '', '') + self.mock_ssh.from_node().execute.return_value = ( + 0, 'throughput_rx_fps\r\n14797660.000\r\n', '') - result = {} - self.assertRaises(RuntimeError, self.scenario.run, result) + with self.assertRaises(y_exc.SLAValidationError) as raised: + self.scenario.run({}) + + self.assertIn('throughput_rx_fps is not defined in SLA', + str(raised.exception)) diff --git a/yardstick/tests/unit/benchmark/scenarios/storage/test_fio.py b/yardstick/tests/unit/benchmark/scenarios/storage/test_fio.py index f149cee69..6e69ddc6d 100644 --- a/yardstick/tests/unit/benchmark/scenarios/storage/test_fio.py +++ b/yardstick/tests/unit/benchmark/scenarios/storage/test_fio.py @@ -18,6 +18,7 @@ import mock from oslo_serialization import jsonutils from yardstick.benchmark.scenarios.storage import fio +from yardstick.common import exceptions as y_exc @mock.patch('yardstick.benchmark.scenarios.storage.fio.ssh') @@ -203,7 +204,7 @@ class FioTestCase(unittest.TestCase): sample_output = self._read_sample_output(self.sample_output['rw']) mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '') - self.assertRaises(AssertionError, p.run, result) + self.assertRaises(y_exc.SLAValidationError, p.run, result) def test_fio_successful_bw_iops_sla(self, mock_ssh): @@ -252,7 +253,7 @@ class FioTestCase(unittest.TestCase): sample_output = self._read_sample_output(self.sample_output['rw']) mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '') - self.assertRaises(AssertionError, p.run, result) + self.assertRaises(y_exc.SLAValidationError, p.run, result) def test_fio_unsuccessful_script_error(self, mock_ssh): diff --git a/yardstick/tests/unit/common/messaging/test_payloads.py b/yardstick/tests/unit/common/messaging/test_payloads.py index 00ec220c9..37b1f1926 100644 --- a/yardstick/tests/unit/common/messaging/test_payloads.py +++ b/yardstick/tests/unit/common/messaging/test_payloads.py @@ -44,3 +44,39 @@ class PayloadTestCase(ut_base.BaseUnitTestCase): _dict = {'version': 2, 'key1': 'value100', 'key2': 'value200'} payload = _DummyPayload.dict_to_obj(_dict) self.assertEqual(set(_dict.keys()), payload._fields) + + +class TrafficGeneratorPayloadTestCase(ut_base.BaseUnitTestCase): + + def test_init(self): + tg_payload = payloads.TrafficGeneratorPayload( + version=1, iteration=10, kpi={'key1': 'value1'}) + self.assertEqual(1, tg_payload.version) + self.assertEqual(10, tg_payload.iteration) + self.assertEqual({'key1': 'value1'}, tg_payload.kpi) + self.assertEqual(3, len(tg_payload._fields)) + + def test__init_missing_required_fields(self): + with self.assertRaises(exceptions.PayloadMissingAttributes): + payloads.TrafficGeneratorPayload(version=1, iteration=10) + with self.assertRaises(exceptions.PayloadMissingAttributes): + payloads.TrafficGeneratorPayload(iteration=10, kpi={}) + with self.assertRaises(exceptions.PayloadMissingAttributes): + payloads.TrafficGeneratorPayload(iteration=10) + + +class RunnerPayloadTestCase(ut_base.BaseUnitTestCase): + + def test_init(self): + runner_payload = payloads.RunnerPayload(version=5, + data={'key1': 'value1'}) + self.assertEqual(5, runner_payload.version) + self.assertEqual({'key1': 'value1'}, runner_payload.data) + + def test__init_missing_required_fields(self): + with self.assertRaises(exceptions.PayloadMissingAttributes): + payloads.RunnerPayload(version=1) + with self.assertRaises(exceptions.PayloadMissingAttributes): + payloads.RunnerPayload(data=None) + with self.assertRaises(exceptions.PayloadMissingAttributes): + payloads.RunnerPayload() diff --git a/yardstick/tests/unit/common/messaging/test_producer.py b/yardstick/tests/unit/common/messaging/test_producer.py index 0289689dc..22286e5c3 100644 --- a/yardstick/tests/unit/common/messaging/test_producer.py +++ b/yardstick/tests/unit/common/messaging/test_producer.py @@ -44,3 +44,10 @@ class MessagingProducerTestCase(ut_base.BaseUnitTestCase): topic='test_topic', fanout=True, server=messaging.SERVER) mock_RPCClient.assert_called_once_with('test_rpc_transport', 'test_Target') + + def test_id(self): + with mock.patch.object(oslo_messaging, 'RPCClient'), \ + mock.patch.object(oslo_messaging, 'get_rpc_transport'), \ + mock.patch.object(oslo_messaging, 'Target'): + msg_producer = _MessagingProducer('topic', 'id_to_check') + self.assertEqual('id_to_check', msg_producer.id) diff --git a/yardstick/tests/unit/common/test_ansible_common.py b/yardstick/tests/unit/common/test_ansible_common.py index 48d8a60c8..bf82f6288 100644 --- a/yardstick/tests/unit/common/test_ansible_common.py +++ b/yardstick/tests/unit/common/test_ansible_common.py @@ -12,28 +12,23 @@ # See the License for the specific language governing permissions and # limitations under the License. - -from __future__ import absolute_import - -import os -import tempfile +import collections import shutil -from collections import defaultdict +import subprocess +import tempfile import mock -import unittest - -from six.moves.configparser import ConfigParser -from six.moves import StringIO +from six import moves +from six.moves import configparser from yardstick.common import ansible_common +from yardstick.tests.unit import base as ut_base -PREFIX = 'yardstick.common.ansible_common' +class OverwriteDictTestCase(ut_base.BaseUnitTestCase): -class OverwriteDictTestCase(unittest.TestCase): def test_overwrite_dict_cfg(self): - c = ConfigParser(allow_no_value=True) + c = configparser.ConfigParser(allow_no_value=True) d = { "section_a": "empty_value", "section_b": {"key_c": "Val_d", "key_d": "VAL_D"}, @@ -43,86 +38,78 @@ class OverwriteDictTestCase(unittest.TestCase): # Python3 and Python2 convert empty values into None or '' # we don't really care but we need to compare correctly for unittest self.assertTrue(c.has_option("section_a", "empty_value")) - self.assertEqual(sorted(c.items("section_b")), [('key_c', 'Val_d'), ('key_d', 'VAL_D')]) + self.assertEqual(sorted(c.items("section_b")), + [('key_c', 'Val_d'), ('key_d', 'VAL_D')]) self.assertTrue(c.has_option("section_c", "key_c")) self.assertTrue(c.has_option("section_c", "key_d")) -class FilenameGeneratorTestCase(unittest.TestCase): - @mock.patch('{}.NamedTemporaryFile'.format(PREFIX)) +class FilenameGeneratorTestCase(ut_base.BaseUnitTestCase): + + @mock.patch.object(tempfile, 'NamedTemporaryFile') def test__handle_existing_file(self, _): - ansible_common.FileNameGenerator._handle_existing_file("/dev/null") + ansible_common.FileNameGenerator._handle_existing_file('/dev/null') def test_get_generator_from_file(self): - ansible_common.FileNameGenerator.get_generator_from_filename("/dev/null", "", "", "") + ansible_common.FileNameGenerator.get_generator_from_filename( + '/dev/null', '', '', '') def test_get_generator_from_file_middle(self): - ansible_common.FileNameGenerator.get_generator_from_filename("/dev/null", "", "", - "null") + ansible_common.FileNameGenerator.get_generator_from_filename( + '/dev/null', '', '', 'null') def test_get_generator_from_file_prefix(self): - ansible_common.FileNameGenerator.get_generator_from_filename("/dev/null", "", "null", - "middle") + ansible_common.FileNameGenerator.get_generator_from_filename( + '/dev/null', '', 'null', 'middle') -class AnsibleNodeTestCase(unittest.TestCase): - def test_ansible_node(self): - ansible_common.AnsibleNode() +class AnsibleNodeTestCase(ut_base.BaseUnitTestCase): def test_ansible_node_len(self): - a = ansible_common.AnsibleNode() - len(a) + self.assertEqual(0, len(ansible_common.AnsibleNode())) def test_ansible_node_repr(self): - a = ansible_common.AnsibleNode() - repr(a) + self.assertEqual('AnsibleNode<{}>', repr(ansible_common.AnsibleNode())) def test_ansible_node_iter(self): - a = ansible_common.AnsibleNode() - for _ in a: - pass + node = ansible_common.AnsibleNode(data={'a': 1, 'b': 2, 'c': 3}) + for key in node: + self.assertIn(key, ('a', 'b', 'c')) def test_is_role(self): - a = ansible_common.AnsibleNode() - self.assertFalse(a.is_role("", default="foo")) + node = ansible_common.AnsibleNode() + self.assertFalse(node.is_role('', default='foo')) def test_ansible_node_get_tuple(self): - a = ansible_common.AnsibleNode({"name": "name"}) - self.assertEqual(a.get_tuple(), ('name', a)) + node = ansible_common.AnsibleNode({'name': 'name'}) + self.assertEqual(node.get_tuple(), ('name', node)) def test_gen_inventory_line(self): - a = ansible_common.AnsibleNode(defaultdict(str)) + a = ansible_common.AnsibleNode(collections.defaultdict(str)) self.assertEqual(a.gen_inventory_line(), "") def test_ansible_node_delitem(self): - a = ansible_common.AnsibleNode({"name": "name"}) - del a['name'] + node = ansible_common.AnsibleNode({'name': 'name'}) + self.assertEqual(1, len(node)) + del node['name'] + self.assertEqual(0, len(node)) def test_ansible_node_getattr(self): - a = ansible_common.AnsibleNode({"name": "name"}) - self.assertIsNone(getattr(a, "nosuch", None)) + node = ansible_common.AnsibleNode({'name': 'name'}) + self.assertIsNone(getattr(node, 'nosuch', None)) -class AnsibleNodeDictTestCase(unittest.TestCase): - def test_ansible_node_dict(self): - n = ansible_common.AnsibleNode - ansible_common.AnsibleNodeDict(n, {}) +class AnsibleNodeDictTestCase(ut_base.BaseUnitTestCase): def test_ansible_node_dict_len(self): n = ansible_common.AnsibleNode a = ansible_common.AnsibleNodeDict(n, {}) - len(a) + self.assertEqual(0, len(a)) def test_ansible_node_dict_repr(self): n = ansible_common.AnsibleNode a = ansible_common.AnsibleNodeDict(n, {}) - repr(a) - - def test_ansible_node_dict_iter(self): - n = ansible_common.AnsibleNode - a = ansible_common.AnsibleNodeDict(n, {}) - for _ in a: - pass + self.assertEqual('{}', repr(a)) def test_ansible_node_dict_get(self): n = ansible_common.AnsibleNode @@ -144,12 +131,15 @@ class AnsibleNodeDictTestCase(unittest.TestCase): ["name ansible_ssh_pass=PASS ansible_user=user"]) -class AnsibleCommonTestCase(unittest.TestCase): - def test_get_timeouts(self): - self.assertAlmostEqual(ansible_common.AnsibleCommon.get_timeout(-100), 1200.0) +class AnsibleCommonTestCase(ut_base.BaseUnitTestCase): - def test__init__(self): - ansible_common.AnsibleCommon({}) + @staticmethod + def _delete_tmpdir(dir): + shutil.rmtree(dir) + + def test_get_timeouts(self): + self.assertAlmostEqual( + ansible_common.AnsibleCommon.get_timeout(-100), 1200.0) def test_reset(self): a = ansible_common.AnsibleCommon({}) @@ -184,81 +174,68 @@ class AnsibleCommonTestCase(unittest.TestCase): a.deploy_dir = "d" self.assertEqual(a.deploy_dir, "d") - @mock.patch('{}.open'.format(PREFIX)) - def test__gen_ansible_playbook_file_list(self, _): + @mock.patch.object(moves.builtins, 'open') + def test__gen_ansible_playbook_file_list(self, *args): d = tempfile.mkdtemp() - try: - a = ansible_common.AnsibleCommon({}) - a._gen_ansible_playbook_file(["a"], d) - finally: - os.rmdir(d) - - @mock.patch('{}.NamedTemporaryFile'.format(PREFIX)) - @mock.patch('{}.open'.format(PREFIX)) - def test__gen_ansible_inventory_file(self, _, __): + self.addCleanup(self._delete_tmpdir, d) + a = ansible_common.AnsibleCommon({}) + a._gen_ansible_playbook_file(["a"], d) + + @mock.patch.object(tempfile, 'NamedTemporaryFile') + @mock.patch.object(moves.builtins, 'open') + def test__gen_ansible_inventory_file(self, *args): nodes = [{ "name": "name", "user": "user", "password": "PASS", "role": "role", }] d = tempfile.mkdtemp() - try: - a = ansible_common.AnsibleCommon(nodes) - a.gen_inventory_ini_dict() - inv_context = a._gen_ansible_inventory_file(d) - with inv_context: - c = StringIO() - inv_context.write_func(c) - self.assertIn("ansible_ssh_pass=PASS", c.getvalue()) - finally: - os.rmdir(d) - - @mock.patch('{}.NamedTemporaryFile'.format(PREFIX)) - @mock.patch('{}.open'.format(PREFIX)) - def test__gen_ansible_playbook_file_list_multiple(self, _, __): + self.addCleanup(self._delete_tmpdir, d) + a = ansible_common.AnsibleCommon(nodes) + a.gen_inventory_ini_dict() + inv_context = a._gen_ansible_inventory_file(d) + with inv_context: + c = moves.StringIO() + inv_context.write_func(c) + self.assertIn("ansible_ssh_pass=PASS", c.getvalue()) + + @mock.patch.object(tempfile, 'NamedTemporaryFile') + @mock.patch.object(moves.builtins, 'open') + def test__gen_ansible_playbook_file_list_multiple(self, *args): d = tempfile.mkdtemp() - try: - a = ansible_common.AnsibleCommon({}) - a._gen_ansible_playbook_file(["a", "b"], d) - finally: - os.rmdir(d) - - @mock.patch('{}.NamedTemporaryFile'.format(PREFIX)) - @mock.patch('{}.Popen'.format(PREFIX)) - @mock.patch('{}.open'.format(PREFIX)) - def test_do_install_tmp_dir(self, _, mock_popen, __): + self.addCleanup(self._delete_tmpdir, d) + a = ansible_common.AnsibleCommon({}) + a._gen_ansible_playbook_file(["a", "b"], d) + + @mock.patch.object(tempfile, 'NamedTemporaryFile') + @mock.patch.object(subprocess, 'Popen') + @mock.patch.object(moves.builtins, 'open') + def test_do_install_tmp_dir(self, _, mock_popen, *args): mock_popen.return_value.communicate.return_value = "", "" mock_popen.return_value.wait.return_value = 0 d = tempfile.mkdtemp() - try: - a = ansible_common.AnsibleCommon({}) - a.do_install('', d) - finally: - os.rmdir(d) - - @mock.patch('{}.NamedTemporaryFile'.format(PREFIX)) - @mock.patch('{}.Popen'.format(PREFIX)) - @mock.patch('{}.open'.format(PREFIX)) - def test_execute_ansible_check(self, _, mock_popen, __): + self.addCleanup(self._delete_tmpdir, d) + a = ansible_common.AnsibleCommon({}) + a.do_install('', d) + + @mock.patch.object(tempfile, 'NamedTemporaryFile') + @mock.patch.object(moves.builtins, 'open') + @mock.patch.object(subprocess, 'Popen') + def test_execute_ansible_check(self, mock_popen, *args): mock_popen.return_value.communicate.return_value = "", "" mock_popen.return_value.wait.return_value = 0 d = tempfile.mkdtemp() - try: - a = ansible_common.AnsibleCommon({}) - a.execute_ansible('', d, ansible_check=True, verbose=True) - finally: - os.rmdir(d) + self.addCleanup(self._delete_tmpdir, d) + a = ansible_common.AnsibleCommon({}) + a.execute_ansible('', d, ansible_check=True, verbose=True) def test_get_sut_info(self): d = tempfile.mkdtemp() a = ansible_common.AnsibleCommon({}) - try: + self.addCleanup(self._delete_tmpdir, d) + with mock.patch.object(a, '_exec_get_sut_info_cmd'): a.get_sut_info(d) - finally: - shutil.rmtree(d) def test_get_sut_info_not_exist(self): a = ansible_common.AnsibleCommon({}) - try: + with self.assertRaises(OSError): a.get_sut_info('/hello/world') - except OSError: - pass diff --git a/yardstick/tests/unit/common/test_exceptions.py b/yardstick/tests/unit/common/test_exceptions.py new file mode 100644 index 000000000..884015536 --- /dev/null +++ b/yardstick/tests/unit/common/test_exceptions.py @@ -0,0 +1,28 @@ +# Copyright 2018 Intel Corporation. +# +# 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. + +from yardstick.common import exceptions +from yardstick.tests.unit import base as ut_base + + +class ErrorClassTestCase(ut_base.BaseUnitTestCase): + + def test_init(self): + with self.assertRaises(RuntimeError): + exceptions.ErrorClass() + + def test_getattr(self): + error_instance = exceptions.ErrorClass(test='') + with self.assertRaises(AttributeError): + error_instance.get_name() diff --git a/yardstick/tests/unit/common/test_kubernetes_utils.py b/yardstick/tests/unit/common/test_kubernetes_utils.py new file mode 100644 index 000000000..ba6b5f388 --- /dev/null +++ b/yardstick/tests/unit/common/test_kubernetes_utils.py @@ -0,0 +1,447 @@ +# Copyright (c) 2018 Intel Corporation +# +# 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. + +import mock +from kubernetes import client +from kubernetes.client import rest +from kubernetes import config + +from yardstick.common import constants +from yardstick.common import exceptions +from yardstick.common import kubernetes_utils +from yardstick.tests.unit import base + + +class GetExtensionsV1betaApiTestCase(base.BaseUnitTestCase): + + @mock.patch.object(client, 'ApiextensionsV1beta1Api', return_value='api') + @mock.patch.object(config, 'load_kube_config') + def test_execute_correct(self, mock_load_kube_config, mock_api): + self.assertEqual('api', kubernetes_utils.get_extensions_v1beta_api()) + mock_load_kube_config.assert_called_once_with( + config_file=constants.K8S_CONF_FILE) + mock_api.assert_called_once() + + @mock.patch.object(config, 'load_kube_config') + def test_execute_exception(self, mock_load_kube_config): + mock_load_kube_config.side_effect = IOError + with self.assertRaises(exceptions.KubernetesConfigFileNotFound): + kubernetes_utils.get_extensions_v1beta_api() + + +class GetCustomObjectsApiTestCase(base.BaseUnitTestCase): + + @mock.patch.object(client, 'CustomObjectsApi', return_value='api') + @mock.patch.object(config, 'load_kube_config') + def test_execute_correct(self, mock_load_kube_config, mock_api): + self.assertEqual('api', kubernetes_utils.get_custom_objects_api()) + mock_load_kube_config.assert_called_once_with( + config_file=constants.K8S_CONF_FILE) + mock_api.assert_called_once() + + @mock.patch.object(config, 'load_kube_config') + def test_execute_exception(self, mock_load_kube_config): + mock_load_kube_config.side_effect = IOError + with self.assertRaises(exceptions.KubernetesConfigFileNotFound): + kubernetes_utils.get_custom_objects_api() + + +class CreateCustomResourceDefinitionTestCase(base.BaseUnitTestCase): + + @mock.patch.object(client, 'V1beta1CustomResourceDefinition', + return_value='crd_obj') + @mock.patch.object(kubernetes_utils, 'get_extensions_v1beta_api') + def test_execute_correct(self, mock_get_api, mock_crd): + mock_create_crd = mock.Mock() + mock_get_api.return_value = mock_create_crd + body = {'spec': 'fake_spec', 'metadata': 'fake_metadata'} + + kubernetes_utils.create_custom_resource_definition(body) + mock_get_api.assert_called_once() + mock_crd.assert_called_once_with(spec='fake_spec', + metadata='fake_metadata') + mock_create_crd.create_custom_resource_definition.\ + assert_called_once_with('crd_obj') + + @mock.patch.object(client, 'V1beta1CustomResourceDefinition', + return_value='crd_obj') + @mock.patch.object(kubernetes_utils, 'get_extensions_v1beta_api') + def test_execute_exception(self, mock_get_api, mock_crd): + mock_create_crd = mock.Mock() + mock_create_crd.create_custom_resource_definition.\ + side_effect = rest.ApiException + mock_get_api.return_value = mock_create_crd + body = {'spec': 'fake_spec', 'metadata': 'fake_metadata'} + + with self.assertRaises(exceptions.KubernetesApiException): + kubernetes_utils.create_custom_resource_definition(body) + mock_get_api.assert_called_once() + mock_crd.assert_called_once_with(spec='fake_spec', + metadata='fake_metadata') + mock_create_crd.create_custom_resource_definition.\ + assert_called_once_with('crd_obj') + + +class DeleteCustomResourceDefinitionTestCase(base.BaseUnitTestCase): + + @mock.patch.object(client, 'V1DeleteOptions', return_value='del_obj') + @mock.patch.object(kubernetes_utils, 'get_extensions_v1beta_api') + def test_execute_correct(self, mock_get_api, mock_delobj): + mock_delete_crd = mock.Mock() + mock_get_api.return_value = mock_delete_crd + + kubernetes_utils.delete_custom_resource_definition('name') + mock_get_api.assert_called_once() + mock_delobj.assert_called_once() + mock_delete_crd.delete_custom_resource_definition.\ + assert_called_once_with('name', 'del_obj') + + @mock.patch.object(client, 'V1DeleteOptions', return_value='del_obj') + @mock.patch.object(kubernetes_utils, 'get_extensions_v1beta_api') + def test_execute_exception(self, mock_get_api, mock_delobj): + mock_delete_crd = mock.Mock() + mock_delete_crd.delete_custom_resource_definition.\ + side_effect = rest.ApiException + mock_get_api.return_value = mock_delete_crd + + with self.assertRaises(exceptions.KubernetesApiException): + kubernetes_utils.delete_custom_resource_definition('name') + mock_delobj.assert_called_once() + mock_delete_crd.delete_custom_resource_definition.\ + assert_called_once_with('name', 'del_obj') + + @mock.patch.object(client, 'V1DeleteOptions', return_value='del_obj') + @mock.patch.object(kubernetes_utils, 'get_extensions_v1beta_api') + @mock.patch.object(kubernetes_utils, 'LOG') + def test_execute_skip_exception(self, mock_log, mock_get_api, mock_delobj): + mock_delete_crd = mock.Mock() + mock_delete_crd.delete_custom_resource_definition.side_effect = rest.ApiException( + status=404) + + mock_get_api.return_value = mock_delete_crd + kubernetes_utils.delete_custom_resource_definition('name', skip_codes=[404]) + + mock_delobj.assert_called_once() + mock_delete_crd.delete_custom_resource_definition.assert_called_once_with( + 'name', 'del_obj') + + mock_log.info.assert_called_once() + + +class GetCustomResourceDefinitionTestCase(base.BaseUnitTestCase): + + @mock.patch.object(kubernetes_utils, 'get_extensions_v1beta_api') + def test_execute_value(self, mock_get_api): + crd_obj = mock.Mock() + crd_obj.spec.names.kind = 'some_kind' + crd_list = mock.Mock() + crd_list.items = [crd_obj] + mock_api = mock.Mock() + mock_api.list_custom_resource_definition.return_value = crd_list + mock_get_api.return_value = mock_api + self.assertEqual( + crd_obj, + kubernetes_utils.get_custom_resource_definition('some_kind')) + + @mock.patch.object(kubernetes_utils, 'get_extensions_v1beta_api') + def test_execute_none(self, mock_get_api): + crd_obj = mock.Mock() + crd_obj.spec.names.kind = 'some_kind' + crd_list = mock.Mock() + crd_list.items = [crd_obj] + mock_api = mock.Mock() + mock_api.list_custom_resource_definition.return_value = crd_list + mock_get_api.return_value = mock_api + self.assertIsNone( + kubernetes_utils.get_custom_resource_definition('other_kind')) + + @mock.patch.object(kubernetes_utils, 'get_extensions_v1beta_api') + def test_execute_exception(self, mock_get_api): + mock_api = mock.Mock() + mock_api.list_custom_resource_definition.\ + side_effect = rest.ApiException + mock_get_api.return_value = mock_api + with self.assertRaises(exceptions.KubernetesApiException): + kubernetes_utils.get_custom_resource_definition('kind') + + +class GetNetworkTestCase(base.BaseUnitTestCase): + @mock.patch.object(kubernetes_utils, 'get_custom_objects_api') + def test_execute_correct(self, mock_get_api): + mock_api = mock.Mock() + mock_get_api.return_value = mock_api + group = 'group.com' + version = mock.Mock() + plural = 'networks' + name = 'net_one' + + kubernetes_utils.get_network( + constants.SCOPE_CLUSTER, group, version, plural, name) + mock_api.get_cluster_custom_object.assert_called_once_with( + group, version, plural, name) + + mock_api.reset_mock() + kubernetes_utils.get_network( + constants.SCOPE_NAMESPACED, group, version, plural, name) + mock_api.get_namespaced_custom_object.assert_called_once_with( + group, version, 'default', plural, name) + + @mock.patch.object(kubernetes_utils, 'get_custom_objects_api') + def test_execute_exception(self, mock_get_api): + mock_api = mock.Mock() + mock_api.get_cluster_custom_object.side_effect = rest.ApiException(404) + mock_api.get_namespaced_custom_object.side_effect = rest.ApiException(404) + mock_get_api.return_value = mock_api + group = 'group.com' + version = mock.Mock() + plural = 'networks' + name = 'net_one' + + network_obj = kubernetes_utils.get_network( + constants.SCOPE_CLUSTER, group, version, plural, name) + self.assertIsNone(network_obj) + + mock_api.reset_mock() + network_obj = kubernetes_utils.get_network( + constants.SCOPE_NAMESPACED, group, version, plural, name) + self.assertIsNone(network_obj) + + +class CreateNetworkTestCase(base.BaseUnitTestCase): + @mock.patch.object(kubernetes_utils, 'get_custom_objects_api') + @mock.patch.object(kubernetes_utils, 'get_network') + def test_execute_correct(self, mock_get_net, mock_get_api): + mock_get_net.return_value = None + mock_api = mock.Mock() + mock_get_api.return_value = mock_api + group = 'group.com' + version = mock.Mock() + plural = 'networks' + body = mock.Mock() + name = 'net_one' + + kubernetes_utils.create_network( + constants.SCOPE_CLUSTER, group, version, plural, body, name) + mock_api.create_cluster_custom_object.assert_called_once_with( + group, version, plural, body) + + mock_api.reset_mock() + kubernetes_utils.create_network( + constants.SCOPE_NAMESPACED, group, version, plural, body, name) + mock_api.create_namespaced_custom_object.assert_called_once_with( + group, version, 'default', plural, body) + + @mock.patch.object(kubernetes_utils, 'get_custom_objects_api') + @mock.patch.object(kubernetes_utils, 'get_network') + def test_network_already_created(self, mock_get_net, mock_get_api): + mock_get_net.return_value = mock.Mock + mock_api = mock.Mock() + mock_get_api.return_value = mock_api + group = 'group.com' + version = mock.Mock() + plural = 'networks' + body = mock.Mock() + name = 'net_one' + + mock_api.reset_mock() + kubernetes_utils.create_network( + constants.SCOPE_CLUSTER, group, version, plural, body, name) + mock_api.create_cluster_custom_object.assert_not_called() + + mock_api.reset_mock() + kubernetes_utils.create_network( + constants.SCOPE_NAMESPACED, group, version, plural, body, name) + mock_api.create_namespaced_custom_object.assert_not_called() + + @mock.patch.object(kubernetes_utils, 'get_custom_objects_api') + @mock.patch.object(kubernetes_utils, 'get_network') + def test_execute_exception(self, mock_get_net, mock_get_api): + mock_get_net.return_value = None + mock_api = mock.Mock() + mock_api.create_cluster_custom_object.side_effect = rest.ApiException + mock_get_api.return_value = mock_api + with self.assertRaises(exceptions.KubernetesApiException): + kubernetes_utils.create_network( + constants.SCOPE_CLUSTER, mock.ANY, mock.ANY, mock.ANY, + mock.ANY, mock.ANY) + + +class DeleteNetworkTestCase(base.BaseUnitTestCase): + @mock.patch.object(kubernetes_utils, 'get_custom_objects_api') + def test_execute_correct(self, mock_get_api): + mock_api = mock.Mock() + mock_get_api.return_value = mock_api + group = 'group.com' + version = mock.Mock() + plural = 'networks' + name = 'network' + + kubernetes_utils.delete_network( + constants.SCOPE_CLUSTER, group, version, plural, name) + mock_api.delete_cluster_custom_object.assert_called_once_with( + group, version, plural, name, {}) + + mock_api.reset_mock() + kubernetes_utils.delete_network( + constants.SCOPE_NAMESPACED, group, version, plural, name) + mock_api.delete_namespaced_custom_object.assert_called_once_with( + group, version, 'default', plural, name, {}) + + @mock.patch.object(kubernetes_utils, 'get_custom_objects_api') + def test_execute_exception(self, mock_get_api): + mock_api = mock.Mock() + mock_api.delete_cluster_custom_object.side_effect = rest.ApiException + mock_get_api.return_value = mock_api + with self.assertRaises(exceptions.KubernetesApiException): + kubernetes_utils.delete_network( + constants.SCOPE_CLUSTER, mock.ANY, mock.ANY, mock.ANY, + mock.ANY) + + @mock.patch.object(kubernetes_utils, 'get_custom_objects_api') + @mock.patch.object(kubernetes_utils, 'LOG') + def test_execute_skip_exception(self, mock_log, mock_get_api): + mock_api = mock.Mock() + mock_api.delete_cluster_custom_object.side_effect = rest.ApiException(status=404) + + mock_get_api.return_value = mock_api + kubernetes_utils.delete_network( + constants.SCOPE_CLUSTER, mock.ANY, mock.ANY, mock.ANY, + mock.ANY, skip_codes=[404]) + + mock_log.info.assert_called_once() + + +class DeletePodTestCase(base.BaseUnitTestCase): + @mock.patch.object(kubernetes_utils, 'get_core_api') + def test_execute_correct(self, mock_get_api): + mock_api = mock.Mock() + mock_get_api.return_value = mock_api + + kubernetes_utils.delete_pod("name", body=None) + mock_api.delete_namespaced_pod.assert_called_once_with( + "name", 'default', None) + + @mock.patch.object(kubernetes_utils, 'get_core_api') + def test_execute_exception(self, mock_get_api): + mock_api = mock.Mock() + mock_api.delete_namespaced_pod.side_effect = rest.ApiException(status=200) + + mock_get_api.return_value = mock_api + with self.assertRaises(exceptions.KubernetesApiException): + kubernetes_utils.delete_pod(mock.ANY, skip_codes=[404]) + + @mock.patch.object(kubernetes_utils, 'LOG') + @mock.patch.object(kubernetes_utils, 'get_core_api') + def test_execute_skip_exception(self, mock_get_api, *args): + mock_api = mock.Mock() + mock_api.delete_namespaced_pod.side_effect = rest.ApiException(status=404) + + mock_get_api.return_value = mock_api + kubernetes_utils.delete_pod(mock.ANY, skip_codes=[404]) + + +class DeleteServiceTestCase(base.BaseUnitTestCase): + @mock.patch.object(client, "V1DeleteOptions") + @mock.patch.object(kubernetes_utils, 'get_core_api') + def test_execute_correct(self, mock_get_api, mock_options): + mock_api = mock.Mock() + mock_get_api.return_value = mock_api + mock_options.return_value = None + kubernetes_utils.delete_service("name", "default", None) + mock_api.delete_namespaced_service.assert_called_once_with( + "name", 'default', None) + + @mock.patch.object(kubernetes_utils, 'get_core_api') + def test_execute_exception(self, mock_get_api): + mock_api = mock.Mock() + mock_api.delete_namespaced_service.side_effect = rest.ApiException(status=200) + + mock_get_api.return_value = mock_api + with self.assertRaises(exceptions.KubernetesApiException): + kubernetes_utils.delete_service(mock.ANY, skip_codes=[404]) + + @mock.patch.object(kubernetes_utils, 'LOG') + @mock.patch.object(kubernetes_utils, 'get_core_api') + def test_execute_skip_exception(self, mock_get_api, *args): + mock_api = mock.Mock() + mock_api.delete_namespaced_service.side_effect = rest.ApiException(status=404) + + mock_get_api.return_value = mock_api + kubernetes_utils.delete_service(mock.ANY, skip_codes=[404]) + + +class DeleteReplicationControllerTestCase(base.BaseUnitTestCase): + @mock.patch.object(kubernetes_utils, 'get_core_api') + def test_execute_correct(self, mock_get_api): + mock_api = mock.Mock() + mock_get_api.return_value = mock_api + kubernetes_utils.delete_replication_controller( + "name", "default", body=None) + + mock_api.delete_namespaced_replication_controller.assert_called_once_with( + "name", "default", None) + + @mock.patch.object(kubernetes_utils, 'get_core_api') + def test_execute_exception(self, mock_get_api): + mock_api = mock.Mock() + mock_api.delete_namespaced_replication_controller.side_effect = ( + rest.ApiException(status=200) + ) + + mock_get_api.return_value = mock_api + with self.assertRaises(exceptions.KubernetesApiException): + kubernetes_utils.delete_replication_controller(mock.ANY, skip_codes=[404]) + + @mock.patch.object(kubernetes_utils, 'get_core_api') + @mock.patch.object(kubernetes_utils, 'LOG') + def test_execute_skip_exception(self, mock_log, mock_get_api): + mock_api = mock.Mock() + mock_api.delete_namespaced_replication_controller.side_effect = ( + rest.ApiException(status=404) + ) + + mock_get_api.return_value = mock_api + kubernetes_utils.delete_replication_controller(mock.ANY, skip_codes=[404]) + + mock_log.info.assert_called_once() + + +class DeleteConfigMapTestCase(base.BaseUnitTestCase): + @mock.patch.object(kubernetes_utils, 'get_core_api') + def test_execute_correct(self, mock_get_api): + mock_api = mock.Mock() + mock_get_api.return_value = mock_api + kubernetes_utils.delete_config_map("name", body=None) + mock_api.delete_namespaced_config_map.assert_called_once_with( + "name", "default", None + ) + + @mock.patch.object(kubernetes_utils, 'get_core_api') + def test_execute_exception(self, mock_get_api): + mock_api = mock.Mock() + mock_api.delete_namespaced_config_map.side_effect = rest.ApiException(status=200) + + mock_get_api.return_value = mock_api + with self.assertRaises(exceptions.KubernetesApiException): + kubernetes_utils.delete_config_map(mock.ANY, skip_codes=[404]) + + @mock.patch.object(kubernetes_utils, 'get_core_api') + @mock.patch.object(kubernetes_utils, 'LOG') + def test_execute_skip_exception(self, mock_log, mock_get_api): + mock_api = mock.Mock() + mock_api.delete_namespaced_config_map.side_effect = rest.ApiException(status=404) + + mock_get_api.return_value = mock_api + kubernetes_utils.delete_config_map(mock.ANY, skip_codes=[404]) + mock_log.info.assert_called_once() diff --git a/yardstick/tests/unit/common/test_openstack_utils.py b/yardstick/tests/unit/common/test_openstack_utils.py index a1a4af2e9..f6a0bdcc1 100644 --- a/yardstick/tests/unit/common/test_openstack_utils.py +++ b/yardstick/tests/unit/common/test_openstack_utils.py @@ -7,11 +7,13 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -from oslo_utils import uuidutils -import unittest +import os + import mock +from oslo_utils import uuidutils import shade from shade import exc +import unittest from yardstick.common import constants from yardstick.common import openstack_utils @@ -28,11 +30,12 @@ class GetCredentialsTestCase(unittest.TestCase): class GetHeatApiVersionTestCase(unittest.TestCase): - def test_get_heat_api_version_check_result(self): + @mock.patch.object(openstack_utils, 'log') + def test_get_heat_api_version_check_result(self, *args): API = 'HEAT_API_VERSION' expected_result = '2' - with mock.patch.dict('os.environ', {API: '2'}, clear=True): + with mock.patch.dict(os.environ, {API: '2'}, clear=True): api_version = openstack_utils.get_heat_api_version() self.assertEqual(api_version, expected_result) @@ -59,6 +62,12 @@ class GetShadeClientTestCase(unittest.TestCase): mock_openstack_cloud.assert_called_once_with( **constants.OS_CLOUD_DEFAULT_CONFIG) + @mock.patch.object(shade, 'operator_cloud', return_value='os_client') + def test_get_shade_operator_client(self, mock_operator_cloud): + self.assertEqual('os_client', openstack_utils.get_shade_operator_client()) + mock_operator_cloud.assert_called_once_with( + **constants.OS_CLOUD_DEFAULT_CONFIG) + class DeleteNeutronNetTestCase(unittest.TestCase): @@ -271,6 +280,12 @@ class CreateSecurityGroupRuleTestCase(unittest.TestCase): self.mock_shade_client = mock.Mock() self.secgroup_name_or_id = 'sg_name_id' self.mock_shade_client.create_security_group_rule = mock.Mock() + self._mock_log = mock.patch.object(openstack_utils, 'log') + self.mock_log = self._mock_log.start() + self.addCleanup(self._stop_mock) + + def _stop_mock(self): + self._mock_log.stop() def test_create_security_group_rule(self): self.mock_shade_client.create_security_group_rule.return_value = ( @@ -279,14 +294,13 @@ class CreateSecurityGroupRuleTestCase(unittest.TestCase): self.mock_shade_client, self.secgroup_name_or_id) self.assertTrue(output) - @mock.patch.object(openstack_utils, 'log') - def test_create_security_group_rule_exception(self, mock_logger): + def test_create_security_group_rule_exception(self): self.mock_shade_client.create_security_group_rule.side_effect = ( exc.OpenStackCloudException('error message')) output = openstack_utils.create_security_group_rule( self.mock_shade_client, self.secgroup_name_or_id) - mock_logger.error.assert_called_once() + self.mock_log.error.assert_called_once() self.assertFalse(output) @@ -315,6 +329,12 @@ class SecurityGroupTestCase(unittest.TestCase): self.sg_name = 'sg_name' self.sg_description = 'sg_description' self._uuid = uuidutils.generate_uuid() + self._mock_log = mock.patch.object(openstack_utils, 'log') + self.mock_log = self._mock_log.start() + self.addCleanup(self._stop_mock) + + def _stop_mock(self): + self._mock_log.stop() def test_create_security_group_full_existing_security_group(self): self.mock_shade_client.get_security_group.return_value = ( @@ -324,21 +344,18 @@ class SecurityGroupTestCase(unittest.TestCase): self.mock_shade_client.get_security_group.assert_called_once() self.assertEqual(self._uuid, output) - @mock.patch.object(openstack_utils, 'log') - def test_create_security_group_full_non_existing_security_group( - self, mock_logger): + def test_create_security_group_full_non_existing_security_group(self): self.mock_shade_client.get_security_group.return_value = None self.mock_shade_client.create_security_group.side_effect = ( exc.OpenStackCloudException('error message')) output = openstack_utils.create_security_group_full( self.mock_shade_client, self.sg_name, self.sg_description) - mock_logger.error.assert_called_once() + self.mock_log.error.assert_called_once() self.assertIsNone(output) @mock.patch.object(openstack_utils, 'create_security_group_rule') - @mock.patch.object(openstack_utils, 'log') def test_create_security_group_full_create_rule_fail( - self, mock_logger, mock_create_security_group_rule): + self, mock_create_security_group_rule): self.mock_shade_client.get_security_group.return_value = None self.mock_shade_client.create_security_group.return_value = ( {'name': 'name', 'id': self._uuid}) @@ -347,7 +364,7 @@ class SecurityGroupTestCase(unittest.TestCase): self.mock_shade_client, self.sg_name, self.sg_description) mock_create_security_group_rule.assert_called() self.mock_shade_client.delete_security_group(self.sg_name) - mock_logger.error.assert_called_once() + self.mock_log.error.assert_called_once() self.assertIsNone(output) @mock.patch.object(openstack_utils, 'create_security_group_rule') @@ -363,10 +380,6 @@ class SecurityGroupTestCase(unittest.TestCase): self.mock_shade_client.delete_security_group(self.sg_name) self.assertEqual(self._uuid, output) -# ********************************************* -# NOVA -# ********************************************* - class CreateInstanceTestCase(unittest.TestCase): @@ -537,10 +550,6 @@ class GetFlavorTestCase(unittest.TestCase): mock_logger.error.assert_called_once() self.assertIsNone(output) -# ********************************************* -# CINDER -# ********************************************* - class GetVolumeIDTestCase(unittest.TestCase): @@ -656,3 +665,66 @@ class DetachVolumeTestCase(unittest.TestCase): 'volume_name_or_id') mock_logger.error.assert_called_once() self.assertFalse(output) + + +class CreateImageTestCase(unittest.TestCase): + + def setUp(self): + self.mock_shade_client = mock.Mock() + self._uuid = uuidutils.generate_uuid() + self.name = 'image_name' + self._mock_log = mock.patch.object(openstack_utils, 'log') + self.mock_log = self._mock_log.start() + self.addCleanup(self._stop_mock) + + def _stop_mock(self): + self._mock_log.stop() + + def test_create_image_already_exit(self): + self.mock_shade_client.get_image_id.return_value = self._uuid + output = openstack_utils.create_image(self.mock_shade_client, self.name) + self.mock_log.info.assert_called_once() + self.assertEqual(self._uuid, output) + + def test_create_image(self): + self.mock_shade_client.get_image_id.return_value = None + self.mock_shade_client.create_image.return_value = {'id': self._uuid} + output = openstack_utils.create_image(self.mock_shade_client, self.name) + self.assertEqual(self._uuid, output) + + def test_create_image_exception(self): + self.mock_shade_client.get_image_id.return_value = None + self.mock_shade_client.create_image.side_effect = ( + exc.OpenStackCloudException('error message')) + + output = openstack_utils.create_image(self.mock_shade_client, + self.name) + self.mock_log.error.assert_called_once() + self.assertIsNone(output) + + +class DeleteImageTestCase(unittest.TestCase): + + def test_delete_image(self): + self.mock_shade_client = mock.Mock() + self.mock_shade_client.delete_image.return_value = True + output = openstack_utils.delete_image(self.mock_shade_client, + 'image_name_or_id') + self.assertTrue(output) + + def test_delete_image_fail(self): + self.mock_shade_client = mock.Mock() + self.mock_shade_client.delete_image.return_value = False + output = openstack_utils.delete_image(self.mock_shade_client, + 'image_name_or_id') + self.assertFalse(output) + + @mock.patch.object(openstack_utils, 'log') + def test_delete_image_exception(self, mock_logger): + self.mock_shade_client = mock.Mock() + self.mock_shade_client.delete_image.side_effect = ( + exc.OpenStackCloudException('error message')) + output = openstack_utils.delete_image(self.mock_shade_client, + 'image_name_or_id') + mock_logger.error.assert_called_once() + self.assertFalse(output) diff --git a/yardstick/tests/unit/common/test_process.py b/yardstick/tests/unit/common/test_process.py index 1c6dfec27..e0933c6ac 100644 --- a/yardstick/tests/unit/common/test_process.py +++ b/yardstick/tests/unit/common/test_process.py @@ -90,10 +90,11 @@ class ExecuteTestCase(unittest.TestCase): additional_env=self.additional_env) self.assertEqual(self.stdout, out) - def test_execute_exception(self): + @mock.patch.object(process, 'LOG') + def test_execute_exception(self, *args): self.obj.returncode = self.RET_CODE_WRONG - self.assertRaises(exceptions.ProcessExecutionError, process.execute, - self.input_cmd, additional_env=self.additional_env) + with self.assertRaises(exceptions.ProcessExecutionError): + process.execute(self.input_cmd, additional_env=self.additional_env) self.obj.communicate.assert_called_once_with(None) def test_execute_with_extra_code(self): @@ -107,7 +108,8 @@ class ExecuteTestCase(unittest.TestCase): additional_env=self.additional_env) self.assertEqual(self.stdout, out) - def test_execute_exception_no_check(self): + @mock.patch.object(process, 'LOG') + def test_execute_exception_no_check(self, *args): self.obj.returncode = self.RET_CODE_WRONG out = process.execute(self.input_cmd, additional_env=self.additional_env, diff --git a/yardstick/tests/unit/common/test_utils.py b/yardstick/tests/unit/common/test_utils.py index 666b29b5f..ef4142148 100644 --- a/yardstick/tests/unit/common/test_utils.py +++ b/yardstick/tests/unit/common/test_utils.py @@ -12,22 +12,25 @@ import errno import importlib import ipaddress from itertools import product, chain -import mock import os +import socket +import time +import threading + +import mock import six from six.moves import configparser -import time import unittest import yardstick from yardstick import ssh -import yardstick.error from yardstick.common import constants from yardstick.common import utils from yardstick.common import exceptions +from yardstick.tests.unit import base as ut_base -class IterSubclassesTestCase(unittest.TestCase): +class IterSubclassesTestCase(ut_base.BaseUnitTestCase): # Disclaimer: this class is a modified copy from # rally/tests/unit/common/plugin/test_discover.py # Copyright 2015: Mirantis Inc. @@ -48,7 +51,7 @@ class IterSubclassesTestCase(unittest.TestCase): self.assertEqual([B, C, D], list(utils.itersubclasses(A))) -class ImportModulesFromPackageTestCase(unittest.TestCase): +class ImportModulesFromPackageTestCase(ut_base.BaseUnitTestCase): @mock.patch('yardstick.common.utils.os.walk') def test_import_modules_from_package_no_mod(self, mock_walk): @@ -73,7 +76,7 @@ class ImportModulesFromPackageTestCase(unittest.TestCase): mock_import_module.assert_called_once_with('bar.baz') -class GetParaFromYaml(unittest.TestCase): +class GetParaFromYaml(ut_base.BaseUnitTestCase): @mock.patch('yardstick.common.utils.os.environ.get') def test_get_param_para_not_found(self, get_env): @@ -97,7 +100,7 @@ class GetParaFromYaml(unittest.TestCase): return file_path -class CommonUtilTestCase(unittest.TestCase): +class CommonUtilTestCase(ut_base.BaseUnitTestCase): def setUp(self): self.data = { @@ -187,14 +190,22 @@ class CommonUtilTestCase(unittest.TestCase): self.assertEqual(mock_open.call_count, mock_open_call_count) -class TestMacAddressToHex(unittest.TestCase): +class TestMacAddressToHex(ut_base.BaseUnitTestCase): def test_mac_address_to_hex_list(self): self.assertEqual(utils.mac_address_to_hex_list("ea:3e:e1:9a:99:e8"), ['0xea', '0x3e', '0xe1', '0x9a', '0x99', '0xe8']) + def test_mac_address_to_hex_list_too_short_mac(self): + with self.assertRaises(exceptions.InvalidMacAddress): + utils.mac_address_to_hex_list("ea:3e:e1:9a") -class TranslateToStrTestCase(unittest.TestCase): + def test_mac_address_to_hex_list_no_int_mac(self): + with self.assertRaises(exceptions.InvalidMacAddress): + utils.mac_address_to_hex_list("invalid_mac") + + +class TranslateToStrTestCase(ut_base.BaseUnitTestCase): def test_translate_to_str_unicode(self): input_str = u'hello' @@ -220,7 +231,7 @@ class TranslateToStrTestCase(unittest.TestCase): self.assertIs(input_value, result) -class TestParseCpuInfo(unittest.TestCase): +class TestParseCpuInfo(ut_base.BaseUnitTestCase): def test_single_socket_no_hyperthread(self): cpuinfo = """\ @@ -805,7 +816,7 @@ power management: self.assertEqual(sockets, [0, 1]) -class ChangeObjToDictTestCase(unittest.TestCase): +class ChangeObjToDictTestCase(ut_base.BaseUnitTestCase): def test_change_obj_to_dict(self): class A(object): @@ -818,7 +829,7 @@ class ChangeObjToDictTestCase(unittest.TestCase): self.assertEqual(obj_r, obj_s) -class SetDictValueTestCase(unittest.TestCase): +class SetDictValueTestCase(ut_base.BaseUnitTestCase): def test_set_dict_value(self): input_dic = { @@ -828,7 +839,7 @@ class SetDictValueTestCase(unittest.TestCase): self.assertEqual(output_dic.get('welcome', {}).get('to'), 'yardstick') -class RemoveFileTestCase(unittest.TestCase): +class RemoveFileTestCase(ut_base.BaseUnitTestCase): def test_remove_file(self): try: @@ -838,7 +849,83 @@ class RemoveFileTestCase(unittest.TestCase): self.assertTrue(isinstance(e, OSError)) -class TestUtils(unittest.TestCase): +class ParseIniFileTestCase(ut_base.BaseUnitTestCase): + + def setUp(self): + self._mock_config_parser_type = mock.patch.object(configparser, + 'ConfigParser') + self.mock_config_parser_type = self._mock_config_parser_type.start() + self.addCleanup(self._stop_mocks) + + def _stop_mocks(self): + self._mock_config_parser_type.stop() + + def test_parse_ini_file(self): + defaults = {'default1': 'value1', + 'default2': 'value2'} + s1 = {'key1': 'value11', + 'key2': 'value22'} + s2 = {'key1': 'value123', + 'key2': 'value234'} + + mock_config_parser = mock.Mock() + self.mock_config_parser_type.return_value = mock_config_parser + mock_config_parser.read.return_value = True + mock_config_parser.sections.return_value = ['s1', 's2'] + mock_config_parser.items.side_effect = iter([ + defaults.items(), + s1.items(), + s2.items(), + ]) + + expected = {'DEFAULT': defaults, + 's1': s1, + 's2': s2} + result = utils.parse_ini_file('my_path') + self.assertDictEqual(expected, result) + + @mock.patch.object(utils, 'logger') + def test_parse_ini_file_missing_section_header(self, *args): + mock_config_parser = mock.Mock() + self.mock_config_parser_type.return_value = mock_config_parser + mock_config_parser.read.side_effect = ( + configparser.MissingSectionHeaderError( + mock.Mock(), 321, mock.Mock())) + + with self.assertRaises(configparser.MissingSectionHeaderError): + utils.parse_ini_file('my_path') + + def test_parse_ini_file_no_file(self): + mock_config_parser = mock.Mock() + self.mock_config_parser_type.return_value = mock_config_parser + mock_config_parser.read.return_value = False + with self.assertRaises(RuntimeError): + utils.parse_ini_file('my_path') + + def test_parse_ini_file_no_default_section_header(self): + s1 = {'key1': 'value11', + 'key2': 'value22'} + s2 = {'key1': 'value123', + 'key2': 'value234'} + + mock_config_parser = mock.Mock() + self.mock_config_parser_type.return_value = mock_config_parser + mock_config_parser.read.return_value = True + mock_config_parser.sections.return_value = ['s1', 's2'] + mock_config_parser.items.side_effect = iter([ + configparser.NoSectionError(mock.Mock()), + s1.items(), + s2.items(), + ]) + + expected = {'DEFAULT': {}, + 's1': s1, + 's2': s2} + result = utils.parse_ini_file('my_path') + self.assertDictEqual(expected, result) + + +class TestUtils(ut_base.BaseUnitTestCase): @mock.patch('yardstick.common.utils.os.makedirs') def test_makedirs(self, *_): @@ -895,7 +982,7 @@ class TestUtils(unittest.TestCase): os.environ.clear() os.environ.update(base_env) - @mock.patch('yardstick.common.utils.configparser.ConfigParser') + @mock.patch.object(configparser, 'ConfigParser') def test_parse_ini_file(self, mock_config_parser_type): defaults = { 'default1': 'value1', @@ -927,23 +1014,26 @@ class TestUtils(unittest.TestCase): result = utils.parse_ini_file('my_path') self.assertDictEqual(result, expected) - @mock.patch('yardstick.common.utils.configparser.ConfigParser') - def test_parse_ini_file_missing_section_header(self, mock_config_parser_type): + @mock.patch.object(utils, 'logger') + @mock.patch.object(configparser, 'ConfigParser') + def test_parse_ini_file_missing_section_header( + self, mock_config_parser_type, *args): mock_config_parser = mock_config_parser_type() - mock_config_parser.read.side_effect = \ - configparser.MissingSectionHeaderError(mock.Mock(), 321, mock.Mock()) + mock_config_parser.read.side_effect = ( + configparser.MissingSectionHeaderError(mock.Mock(), 321, + mock.Mock())) with self.assertRaises(configparser.MissingSectionHeaderError): utils.parse_ini_file('my_path') - @mock.patch('yardstick.common.utils.configparser.ConfigParser') + @mock.patch.object(configparser, 'ConfigParser') def test_parse_ini_file_no_file(self, mock_config_parser_type): mock_config_parser = mock_config_parser_type() mock_config_parser.read.return_value = False with self.assertRaises(RuntimeError): utils.parse_ini_file('my_path') - @mock.patch('yardstick.common.utils.configparser.ConfigParser') + @mock.patch.object(configparser, 'ConfigParser') def test_parse_ini_file_no_default_section_header(self, mock_config_parser_type): s1 = { 'key1': 'value11', @@ -989,16 +1079,8 @@ class TestUtils(unittest.TestCase): with self.assertRaises(RuntimeError): utils.validate_non_string_sequence(1, raise_exc=RuntimeError) - def test_error_class(self): - with self.assertRaises(RuntimeError): - yardstick.error.ErrorClass() - - error_instance = yardstick.error.ErrorClass(test='') - with self.assertRaises(AttributeError): - error_instance.get_name() - -class TestUtilsIpAddrMethods(unittest.TestCase): +class TestUtilsIpAddrMethods(ut_base.BaseUnitTestCase): GOOD_IP_V4_ADDRESS_STR_LIST = [ u'0.0.0.0', @@ -1041,6 +1123,19 @@ class TestUtilsIpAddrMethods(unittest.TestCase): u'123:4567:89ab:cdef:123:4567:89ab:cdef/129', ] + def test_make_ipv4_address(self): + for addr in self.GOOD_IP_V4_ADDRESS_STR_LIST: + # test with no mask + expected = ipaddress.IPv4Address(addr) + self.assertEqual(utils.make_ipv4_address(addr), expected, addr) + + def test_make_ipv4_address_error(self): + addr_list = self.INVALID_IP_ADDRESS_STR_LIST +\ + self.GOOD_IP_V6_ADDRESS_STR_LIST + for addr in addr_list: + self.assertRaises(Exception, utils.make_ipv4_address, addr) + + def test_safe_ip_address(self): addr_list = self.GOOD_IP_V4_ADDRESS_STR_LIST for addr in addr_list: @@ -1124,8 +1219,22 @@ class TestUtilsIpAddrMethods(unittest.TestCase): for value in chain(value_iter, self.INVALID_IP_ADDRESS_STR_LIST): self.assertEqual(utils.ip_to_hex(value), value) + def test_get_mask_from_ip_range_ipv4(self): + ip_str = '1.1.1.1' + for mask in range(8, 30): + ip = ipaddress.ip_network(ip_str + '/' + str(mask), strict=False) + result = utils.get_mask_from_ip_range(ip[2], ip[-2]) + self.assertEqual(mask, result) + + def test_get_mask_from_ip_range_ipv6(self): + ip_str = '2001::1' + for mask in range(8, 120): + ip = ipaddress.ip_network(ip_str + '/' + str(mask), strict=False) + result = utils.get_mask_from_ip_range(ip[2], ip[-2]) + self.assertEqual(mask, result) + -class SafeDecodeUtf8TestCase(unittest.TestCase): +class SafeDecodeUtf8TestCase(ut_base.BaseUnitTestCase): @unittest.skipIf(six.PY2, 'This test should only be launched with Python 3.x') @@ -1136,7 +1245,7 @@ class SafeDecodeUtf8TestCase(unittest.TestCase): self.assertEqual('this is a byte array', out) -class ReadMeminfoTestCase(unittest.TestCase): +class ReadMeminfoTestCase(ut_base.BaseUnitTestCase): MEMINFO = (b'MemTotal: 65860500 kB\n' b'MemFree: 28690900 kB\n' @@ -1162,7 +1271,7 @@ class ReadMeminfoTestCase(unittest.TestCase): self.assertEqual(self.MEMINFO_DICT, output) -class TimerTestCase(unittest.TestCase): +class TimerTestCase(ut_base.BaseUnitTestCase): def test__getattr(self): with utils.Timer() as timer: @@ -1180,8 +1289,23 @@ class TimerTestCase(unittest.TestCase): with utils.Timer(timeout=1): time.sleep(2) + def test__enter_with_timeout_no_exception(self): + with utils.Timer(timeout=1, raise_exception=False): + time.sleep(2) -class WaitUntilTrueTestCase(unittest.TestCase): + def test__iter(self): + iterations = [] + for i in utils.Timer(timeout=2): + iterations.append(i) + time.sleep(1.1) + self.assertEqual(2, len(iterations)) + + def test_delta_time_sec(self): + with utils.Timer() as timer: + self.assertIsInstance(timer.delta_time_sec(), float) + + +class WaitUntilTrueTestCase(ut_base.BaseUnitTestCase): def test_no_timeout(self): self.assertIsNone(utils.wait_until_true(lambda: True, @@ -1200,3 +1324,70 @@ class WaitUntilTrueTestCase(unittest.TestCase): self.assertIsNone( utils.wait_until_true(lambda: False, timeout=1, sleep=1, exception=MyTimeoutException)) + + def _run_thread(self): + with self.assertRaises(exceptions.WaitTimeout): + utils.wait_until_true(lambda: False, timeout=1, sleep=1) + + def test_timeout_no_main_thread(self): + new_thread = threading.Thread(target=self._run_thread) + new_thread.start() + new_thread.join(timeout=3) + + +class SendSocketCommandTestCase(unittest.TestCase): + + @mock.patch.object(socket, 'socket') + def test_execute_correct(self, mock_socket): + mock_socket_obj = mock.Mock() + mock_socket_obj.connect_ex.return_value = 0 + mock_socket.return_value = mock_socket_obj + self.assertEqual(0, utils.send_socket_command('host', 22, 'command')) + mock_socket.assert_called_once_with(socket.AF_INET, socket.SOCK_STREAM) + mock_socket_obj.connect_ex.assert_called_once_with(('host', 22)) + mock_socket_obj.sendall.assert_called_once_with(six.b('command')) + mock_socket_obj.close.assert_called_once() + + @mock.patch.object(socket, 'socket') + def test_execute_exception(self, mock_socket): + mock_socket_obj = mock.Mock() + mock_socket_obj.connect_ex.return_value = 0 + mock_socket.return_value = mock_socket_obj + mock_socket_obj.sendall.side_effect = socket.error + self.assertEqual(1, utils.send_socket_command('host', 22, 'command')) + mock_socket.assert_called_once_with(socket.AF_INET, socket.SOCK_STREAM) + mock_socket_obj.connect_ex.assert_called_once_with(('host', 22)) + mock_socket_obj.sendall.assert_called_once_with(six.b('command')) + mock_socket_obj.close.assert_called_once() + + +class GetPortMacTestCase(unittest.TestCase): + + def setUp(self): + self.ssh_client = mock.Mock() + self.ssh_client.execute.return_value = (0, 'foo ', '') + + def test_ssh_client_execute_called(self): + utils.get_port_mac(self.ssh_client, 99) + self.ssh_client.execute.assert_called_once_with( + "ifconfig |grep HWaddr |grep 99 |awk '{print $5}' ", + raise_on_error=True) + + def test_return_value(self): + self.assertEqual('foo', utils.get_port_mac(self.ssh_client, 99)) + + +class GetPortIPTestCase(unittest.TestCase): + + def setUp(self): + self.ssh_client = mock.Mock() + self.ssh_client.execute.return_value = (0, 'foo ', '') + + def test_ssh_client_execute_called(self): + utils.get_port_ip(self.ssh_client, 99) + self.ssh_client.execute.assert_called_once_with( + "ifconfig 99 |grep 'inet addr' |awk '{print $2}' |cut -d ':' -f2 ", + raise_on_error=True) + + def test_return_value(self): + self.assertEqual('foo', utils.get_port_ip(self.ssh_client, 99)) diff --git a/yardstick/tests/unit/network_services/collector/test_subscriber.py b/yardstick/tests/unit/network_services/collector/test_subscriber.py index 14e26f7fe..cffa4d492 100644 --- a/yardstick/tests/unit/network_services/collector/test_subscriber.py +++ b/yardstick/tests/unit/network_services/collector/test_subscriber.py @@ -11,10 +11,10 @@ # 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. -# -import unittest +import copy import mock +import unittest from yardstick.network_services.collector import subscriber from yardstick import ssh @@ -38,6 +38,16 @@ class MockVnfAprrox(object): class CollectorTestCase(unittest.TestCase): + NODES = { + 'context1': [{'name': 'node1', + 'ip': '1.2.3.4', + 'collectd': { + 'plugins': {'abc': 12, 'def': 34}, + 'interval': 987} + } + ] + } + def setUp(self): vnf = MockVnfAprrox() vnf.start_collect = mock.Mock() @@ -47,30 +57,62 @@ class CollectorTestCase(unittest.TestCase): mock_instance = mock.Mock() mock_instance.execute.return_value = 0, '', '' mock_ssh.from_node.return_value = mock_instance - self.collector = subscriber.Collector([vnf]) + self.collector = subscriber.Collector([vnf], self.NODES) def tearDown(self): self.ssh_patch.stop() - def test___init__(self, *_): + def test___init__(self, *args): + vnf = MockVnfAprrox() + collector = subscriber.Collector([vnf], self.NODES) + self.assertEqual(len(collector.vnfs), 1) + self.assertEqual(len(collector.nodes), 1) + + def test___init__no_node_information(self, *args): vnf = MockVnfAprrox() - collector = subscriber.Collector([vnf]) + nodes = copy.deepcopy(self.NODES) + nodes['context1'].append(None) + collector = subscriber.Collector([vnf], nodes) self.assertEqual(len(collector.vnfs), 1) + self.assertEqual(len(collector.nodes), 1) + + def test___init__no_node_information_in_context(self, *args): + vnf = MockVnfAprrox() + nodes = copy.deepcopy(self.NODES) + nodes['context1'] = None + collector = subscriber.Collector([vnf], nodes) + self.assertEqual(len(collector.vnfs), 1) + self.assertEqual(len(collector.nodes), 1) + + def test_start(self, *args): + resource_profile = mock.MagicMock() + self.collector.resource_profiles = {'key': resource_profile} + self.collector.bin_path = 'path' - def test_start(self, *_): self.assertIsNone(self.collector.start()) for vnf in self.collector.vnfs: vnf.start_collect.assert_called_once() + for resource_profile in self.collector.resource_profiles.values(): + resource_profile.initiate_systemagent.assert_called_once_with('path') + resource_profile.start.assert_called_once() + resource_profile.amqp_process_for_nfvi_kpi.assert_called_once() + def test_stop(self, *_): + resource_profile = mock.MagicMock() + self.collector.resource_profiles = {'key': resource_profile} + self.assertIsNone(self.collector.stop()) for vnf in self.collector.vnfs: vnf.stop_collect.assert_called_once() - def test_get_kpi(self, *_): + for resource in self.collector.resource_profiles.values(): + resource.stop.assert_called_once() + + def test_get_kpi(self, *args): result = self.collector.get_kpi() - self.assertEqual(1, len(result)) + self.assertEqual(2, len(result)) self.assertEqual(4, len(result["vnf__1"])) self.assertEqual(result["vnf__1"]["pkt_in_up_stream"], 100) self.assertEqual(result["vnf__1"]["pkt_drop_up_stream"], 5) diff --git a/yardstick/tests/unit/network_services/helpers/test_dpdkbindnic_helper.py b/yardstick/tests/unit/network_services/helpers/test_dpdkbindnic_helper.py index 367072e84..e19311613 100644 --- a/yardstick/tests/unit/network_services/helpers/test_dpdkbindnic_helper.py +++ b/yardstick/tests/unit/network_services/helpers/test_dpdkbindnic_helper.py @@ -17,9 +17,7 @@ import unittest import os -from yardstick.error import IncorrectConfig, SSHError -from yardstick.error import IncorrectNodeSetup -from yardstick.error import IncorrectSetup +from yardstick.common import exceptions from yardstick.network_services.helpers.dpdkbindnic_helper import DpdkInterface from yardstick.network_services.helpers.dpdkbindnic_helper import DpdkNode from yardstick.network_services.helpers.dpdkbindnic_helper import DpdkBindHelper @@ -142,12 +140,13 @@ class TestDpdkInterface(unittest.TestCase): def test_probe_missing_values_negative(self): mock_dpdk_node = mock.Mock() - mock_dpdk_node.netdevs.values.side_effect = IncorrectNodeSetup + mock_dpdk_node.netdevs.values.side_effect = ( + exceptions.IncorrectNodeSetup(error_msg='')) interface = {'local_mac': '0a:de:ad:be:ef:f5'} dpdk_intf = DpdkInterface(mock_dpdk_node, interface) - with self.assertRaises(IncorrectConfig): + with self.assertRaises(exceptions.IncorrectConfig): dpdk_intf.probe_missing_values() @@ -213,7 +212,7 @@ class TestDpdkNode(unittest.TestCase): def test_check(self): def update(): if not mock_force_rebind.called: - raise IncorrectConfig + raise exceptions.IncorrectConfig(error_msg='') interfaces[0]['virtual-interface'].update({ 'vpci': '0000:01:02.1', @@ -244,11 +243,11 @@ class TestDpdkNode(unittest.TestCase): mock_ssh_helper = mock.Mock() mock_ssh_helper.execute.return_value = 0, '', '' - mock_intf_type().check.side_effect = SSHError + mock_intf_type().check.side_effect = exceptions.SSHError dpdk_node = DpdkNode(NAME, self.INTERFACES, mock_ssh_helper) - with self.assertRaises(IncorrectSetup): + with self.assertRaises(exceptions.IncorrectSetup): dpdk_node.check() def test_probe_netdevs(self): @@ -290,7 +289,7 @@ class TestDpdkNode(unittest.TestCase): dpdk_helper.force_dpdk_rebind = mock_helper_func = mock.Mock() dpdk_node._force_rebind() - self.assertEqual(mock_helper_func.call_count, 1) + mock_helper_func.assert_called_once() class TestDpdkBindHelper(unittest.TestCase): diff --git a/yardstick/tests/unit/network_services/helpers/test_samplevnf_helper.py b/yardstick/tests/unit/network_services/helpers/test_samplevnf_helper.py index 6d5e1da60..e66e7fbb8 100644 --- a/yardstick/tests/unit/network_services/helpers/test_samplevnf_helper.py +++ b/yardstick/tests/unit/network_services/helpers/test_samplevnf_helper.py @@ -223,7 +223,7 @@ class TestMultiPortConfig(unittest.TestCase): mock.Mock(return_value={'link_config': 0, 'arp_config': '', 'arp_config6': '', 'actions': '', 'arp_route_tbl': '', 'arp_route_tbl6': '', - 'rules': ''}) + 'flows': ''}) opnfv_vnf.port_pair_list = [("xe0", "xe1")] self.assertIsNotNone(opnfv_vnf.generate_script(self.VNFD)) opnfv_vnf.lb_config = 'HW' @@ -249,66 +249,6 @@ class TestMultiPortConfig(unittest.TestCase): opnfv_vnf.generate_rule_config = mock.Mock() self.assertIsNotNone(opnfv_vnf.generate_script_data()) - def test_generate_rule_config(self): - topology_file = mock.Mock() - config_tpl = mock.Mock() - tmp_file = mock.Mock() - vnfd_mock = mock.MagicMock() - opnfv_vnf = samplevnf_helper.MultiPortConfig( - topology_file, config_tpl, tmp_file, vnfd_mock) - opnfv_vnf.get_config_tpl_data = mock.MagicMock() - opnfv_vnf.socket = 0 - opnfv_vnf.start_core = 0 - opnfv_vnf.update_write_parser = mock.MagicMock() - opnfv_vnf.generate_script_data = \ - mock.Mock(return_value={'link_config': 0, 'arp_config': '', - 'arp_config6': '', 'actions': '', - 'rules': ''}) - opnfv_vnf.port_pair_list = [("xe0", "xe1")] - opnfv_vnf.get_port_pairs = mock.Mock() - opnfv_vnf.vnf_type = 'ACL' - opnfv_vnf.get_ports_gateway = mock.Mock(return_value=u'1.1.1.1') - opnfv_vnf.get_netmask_gateway = mock.Mock( - return_value=u'255.255.255.0') - opnfv_vnf.get_ports_gateway6 = mock.Mock(return_value=u'1.1.1.1') - opnfv_vnf.get_netmask_gateway6 = mock.Mock( - return_value=u'255.255.255.0') - opnfv_vnf.txrx_pipeline = '' - opnfv_vnf.vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - opnfv_vnf.interfaces = opnfv_vnf.vnfd['vdu'][0]['external-interface'] - opnfv_vnf.rules = '' - self.assertIsNotNone(opnfv_vnf.generate_rule_config()) - opnfv_vnf.rules = 'new' - self.assertIsNotNone(opnfv_vnf.generate_rule_config()) - - def test_generate_action_config(self): - topology_file = mock.Mock() - config_tpl = mock.Mock() - tmp_file = mock.Mock() - vnfd_mock = mock.MagicMock() - opnfv_vnf = samplevnf_helper.MultiPortConfig( - topology_file, config_tpl, tmp_file, vnfd_mock) - opnfv_vnf.get_config_tpl_data = mock.MagicMock() - opnfv_vnf.socket = 0 - opnfv_vnf.start_core = 0 - opnfv_vnf.update_write_parser = mock.MagicMock() - opnfv_vnf.generate_script_data = \ - mock.Mock(return_value={'link_config': 0, 'arp_config': '', - 'arp_config6': '', 'actions': '', - 'rules': ''}) - opnfv_vnf.port_pair_list = [("xe0", "xe1")] - opnfv_vnf.get_port_pairs = mock.Mock() - opnfv_vnf.vnf_type = 'VFW' - opnfv_vnf.get_ports_gateway = mock.Mock(return_value=u'1.1.1.1') - opnfv_vnf.get_netmask_gateway = mock.Mock( - return_value=u'255.255.255.0') - opnfv_vnf.get_ports_gateway6 = mock.Mock(return_value=u'1.1.1.1') - opnfv_vnf.get_netmask_gateway6 = mock.Mock( - return_value=u'255.255.255.0') - opnfv_vnf.txrx_pipeline = '' - opnfv_vnf.rules = '' - self.assertIsNotNone(opnfv_vnf.generate_action_config()) - def test_generate_arp_config6(self): topology_file = mock.Mock() config_tpl = mock.Mock() diff --git a/yardstick/tests/unit/network_services/libs/ixia_libs/test_IxNet.py b/yardstick/tests/unit/network_services/libs/ixia_libs/test_IxNet.py deleted file mode 100644 index 7ca2f0f19..000000000 --- a/yardstick/tests/unit/network_services/libs/ixia_libs/test_IxNet.py +++ /dev/null @@ -1,874 +0,0 @@ -# Copyright (c) 2016-2017 Intel Corporation -# -# 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. -# - -import mock -import IxNetwork -import unittest - -from yardstick.network_services.libs.ixia_libs.IxNet.IxNet import IxNextgen -from yardstick.network_services.libs.ixia_libs.IxNet.IxNet import IP_VERSION_4 -from yardstick.network_services.libs.ixia_libs.IxNet.IxNet import IP_VERSION_6 - -UPLINK = "uplink" -DOWNLINK = "downlink" - - -class TestIxNextgen(unittest.TestCase): - - def test___init__(self): - ixnet_gen = IxNextgen() - self.assertIsNone(ixnet_gen._bidir) - - @mock.patch.object(IxNetwork, 'IxNet') - def test_connect(self, mock_ixnet): - ixnet_instance = mock.Mock() - mock_ixnet.return_value = ixnet_instance - ixnet_gen = IxNextgen() - with mock.patch.object(ixnet_gen, 'get_config') as mock_config: - mock_config.return_value = {'machine': 'machine_fake', - 'port': 'port_fake', - 'version': 12345} - ixnet_gen._connect(mock.ANY) - - ixnet_instance.connect.assert_called_once_with( - 'machine_fake', '-port', 'port_fake', '-version', '12345') - mock_config.assert_called_once() - - def test_clear_ixia_config(self): - ixnet = mock.MagicMock() - ixnet.execute = mock.Mock() - - ixnet_gen = IxNextgen(ixnet) - - result = ixnet_gen.clear_ixia_config() - self.assertIsNone(result) - self.assertEqual(ixnet.execute.call_count, 1) - - def test_load_ixia_profile(self): - ixnet = mock.MagicMock() - ixnet.execute = mock.Mock() - - ixnet_gen = IxNextgen(ixnet) - - result = ixnet_gen.load_ixia_profile({}) - self.assertIsNone(result) - self.assertEqual(ixnet.execute.call_count, 1) - - def test_load_ixia_config(self): - ixnet = mock.MagicMock() - ixnet.execute = mock.Mock() - - ixnet_gen = IxNextgen(ixnet) - - result = ixnet_gen.ix_load_config({}) - self.assertIsNone(result) - self.assertEqual(ixnet.execute.call_count, 2) - - @mock.patch('yardstick.network_services.libs.ixia_libs.IxNet.IxNet.log') - def test_ix_assign_ports(self, mock_logger): - ixnet = mock.MagicMock() - ixnet.getList.return_value = [0, 1] - ixnet.getAttribute.side_effect = ['up', 'down'] - - config = { - 'chassis': '1.1.1.1', - 'cards': ['1', '2'], - 'ports': ['2', '2'], - } - - ixnet_gen = IxNextgen(ixnet) - ixnet_gen._cfg = config - - result = ixnet_gen.ix_assign_ports() - self.assertIsNone(result) - self.assertEqual(ixnet.execute.call_count, 1) - self.assertEqual(ixnet.commit.call_count, 1) - self.assertEqual(ixnet.getAttribute.call_count, 2) - self.assertEqual(mock_logger.error.call_count, 1) - - def test_ix_update_frame(self): - static_traffic_params = { - UPLINK: { - "id": 1, - "bidir": "False", - "duration": 60, - "iload": "100", - "outer_l2": { - "dstmac": "00:00:00:00:00:03", - "framesPerSecond": True, - "framesize": { - "64B": "100", - "1KB": "0", - }, - "srcmac": "00:00:00:00:00:01" - }, - "outer_l3": { - "dscp": 0, - "dstip4": "152.16.40.20", - "proto": "udp", - "srcip4": "152.16.100.20", - "ttl": 32 - }, - "outer_l3v4": { - "dscp": 0, - "dstip4": "152.16.40.20", - "proto": "udp", - "srcip4": "152.16.100.20", - "ttl": 32 - }, - "outer_l3v6": { - "count": 1024, - "dscp": 0, - "dstip4": "152.16.100.20", - "proto": "udp", - "srcip4": "152.16.40.20", - "ttl": 32 - }, - "outer_l4": { - "dstport": "2001", - "srcport": "1234" - }, - "traffic_type": "continuous" - }, - DOWNLINK: { - "id": 2, - "bidir": "False", - "duration": 60, - "iload": "100", - "outer_l2": { - "dstmac": "00:00:00:00:00:04", - "framesPerSecond": False, - "framesize": {"64B": "100"}, - "srcmac": "00:00:00:00:00:01" - }, - "outer_l3": { - "count": 1024, - "dscp": 0, - "dstip4": "152.16.100.20", - "proto": "udp", - "srcip4": "152.16.40.20", - "ttl": 32 - }, - "outer_l3v4": { - "count": 1024, - "dscp": 0, - "dstip4": "152.16.100.20", - "proto": "udp", - "srcip4": "152.16.40.20", - "ttl": 32 - }, - "outer_l3v6": { - "count": 1024, - "dscp": 0, - "dstip4": "152.16.100.20", - "proto": "udp", - "srcip4": "152.16.40.20", - "ttl": 32 - }, - "outer_l4": { - "dstport": "1234", - "srcport": "2001" - }, - "traffic_type": "continuous" - } - } - - ixnet = mock.MagicMock() - ixnet.remapIds.return_value = ["0"] - ixnet.setMultiAttribute.return_value = [1] - ixnet.commit.return_value = [1] - ixnet.getList.side_effect = [ - [1], - [1], - [1], - [ - "ethernet.header.destinationAddress", - "ethernet.header.sourceAddress", - ], - ] - - ixnet_gen = IxNextgen(ixnet) - - result = ixnet_gen.ix_update_frame(static_traffic_params) - self.assertIsNone(result) - self.assertEqual(ixnet.setMultiAttribute.call_count, 7) - self.assertEqual(ixnet.commit.call_count, 2) - - def test_ix_update_udp(self): - ixnet = mock.MagicMock() - - ixnet_gen = IxNextgen(ixnet) - - result = ixnet_gen.ix_update_udp({}) - self.assertIsNone(result) - - def test_ix_update_tcp(self): - ixnet = mock.MagicMock() - ixnet_gen = IxNextgen(ixnet) - - result = ixnet_gen.ix_update_tcp({}) - self.assertIsNone(result) - - def test_ix_start_traffic(self): - ixnet = mock.MagicMock() - ixnet.getList.return_value = [0] - ixnet.getAttribute.return_value = 'down' - - ixnet_gen = IxNextgen(ixnet) - - result = ixnet_gen.ix_start_traffic() - self.assertIsNone(result) - self.assertEqual(ixnet.getList.call_count, 1) - self.assertEqual(ixnet.execute.call_count, 3) - - def test_ix_stop_traffic(self): - ixnet = mock.MagicMock() - ixnet.getList.return_value = [0] - - ixnet_gen = IxNextgen(ixnet) - - result = ixnet_gen.ix_stop_traffic() - self.assertIsNone(result) - self.assertEqual(ixnet.getList.call_count, 1) - self.assertEqual(ixnet.execute.call_count, 1) - - def test_ix_get_statistics(self): - ixnet = mock.MagicMock() - ixnet.execute.return_value = "" - ixnet.getList.side_effect = [ - [ - '::ixNet::OBJ-/statistics/view:"Traffic Item Statistics"', - '::ixNet::OBJ-/statistics/view:"Port Statistics"', - ], - [ - '::ixNet::OBJ-/statistics/view:"Flow Statistics"', - ], - ] - - ixnet_gen = IxNextgen(ixnet) - - result = ixnet_gen.ix_get_statistics() - self.assertIsNotNone(result) - self.assertEqual(ixnet.getList.call_count, 1) - self.assertEqual(ixnet.execute.call_count, 20) - - def test_find_view_obj_no_where(self): - views = ['here', 'there', 'everywhere'] - result = IxNextgen.find_view_obj('no_where', views) - self.assertEqual(result, '') - - def test_add_ip_header_v4(self): - static_traffic_params = { - "uplink_0": { - "id": 1, - "bidir": "False", - "duration": 60, - "iload": "100", - "outer_l2": { - "dstmac": "00:00:00:00:00:03", - "framesPerSecond": True, - "framesize": {"64B": "100"}, - "srcmac": "00:00:00:00:00:01" - }, - "outer_l3": { - "dscp": 0, - "dstip4": "152.16.40.20", - "proto": "udp", - "srcip4": "152.16.100.20", - "count": 1024, - "ttl": 32 - }, - "outer_l3v4": { - "dscp": 0, - "dstip4": "152.16.40.20", - "proto": "udp", - "srcip4": "152.16.100.20", - "ttl": 32 - }, - "outer_l3v6": { - "count": 1024, - "dscp": 0, - "dstip4": "152.16.100.20", - "proto": "udp", - "srcip4": "152.16.40.20", - "ttl": 32 - }, - "outer_l4": { - "dstport": "2001", - "srcport": "1234" - }, - "traffic_type": "continuous" - }, - "downlink_0": { - "id": 2, - "bidir": "False", - "duration": 60, - "iload": "100", - "outer_l2": { - "dstmac": "00:00:00:00:00:04", - "framesPerSecond": True, - "framesize": {"64B": "100"}, - "srcmac": "00:00:00:00:00:01" - }, - "outer_l3": { - "count": 1024, - "dscp": 0, - "dstip4": "152.16.100.20", - "proto": "udp", - "srcip4": "152.16.40.20", - "ttl": 32 - }, - "outer_l3v4": { - "count": 1024, - "dscp": 0, - "dstip4": "152.16.100.20", - "proto": "udp", - "srcip4": "152.16.40.20", - "ttl": 32 - }, - "outer_l3v6": { - "count": 1024, - "dscp": 0, - "dstip4": "152.16.100.20", - "proto": "udp", - "srcip4": "152.16.40.20", - "ttl": 32 - }, - "outer_l4": { - "dstport": "1234", - "srcport": "2001" - }, - "traffic_type": "continuous" - } - } - - ixnet = mock.MagicMock() - ixnet.remapIds.return_value = ["0"] - ixnet.setMultiAttribute.return_value = [1] - ixnet.commit.return_value = [1] - ixnet.getList.side_effect = [[1], [0], [0], ["srcIp", "dstIp"]] - - ixnet_gen = IxNextgen(ixnet) - - result = ixnet_gen.add_ip_header(static_traffic_params, IP_VERSION_4) - self.assertIsNone(result) - self.assertGreater(ixnet.setMultiAttribute.call_count, 0) - self.assertEqual(ixnet.commit.call_count, 1) - - def test_add_ip_header_v4_nothing_to_do(self): - static_traffic_params = { - "uplink_0": { - "id": 1, - "bidir": "False", - "duration": 60, - "iload": "100", - "outer_l2": { - "dstmac": "00:00:00:00:00:03", - "framesPerSecond": True, - "framesize": {"64B": "100"}, - "srcmac": "00:00:00:00:00:01" - }, - "outer_l3": { - "dscp": 0, - "dstip4": "152.16.40.20", - "proto": "udp", - "srcip4": "152.16.100.20", - "count": 1024, - "ttl": 32 - }, - "outer_l3v4": { - "dscp": 0, - "dstip4": "152.16.40.20", - "proto": "udp", - "srcip4": "152.16.100.20", - "ttl": 32 - }, - "outer_l3v6": { - "count": 1024, - "dscp": 0, - "dstip4": "152.16.100.20", - "proto": "udp", - "srcip4": "152.16.40.20", - "ttl": 32 - }, - "outer_l4": { - "dstport": "2001", - "srcport": "1234" - }, - "traffic_type": "continuous" - }, - "downlink_0": { - "id": 2, - "bidir": "False", - "duration": 60, - "iload": "100", - "outer_l2": { - "dstmac": "00:00:00:00:00:04", - "framesPerSecond": True, - "framesize": {"64B": "100"}, - "srcmac": "00:00:00:00:00:01" - }, - "outer_l3": { - "count": 1024, - "dscp": 0, - "dstip4": "152.16.100.20", - "proto": "udp", - "srcip4": "152.16.40.20", - "ttl": 32 - }, - "outer_l3v4": { - "count": 1024, - "dscp": 0, - "dstip4": "152.16.100.20", - "proto": "udp", - "srcip4": "152.16.40.20", - "ttl": 32 - }, - "outer_l3v6": { - "count": 1024, - "dscp": 0, - "dstip4": "152.16.100.20", - "proto": "udp", - "srcip4": "152.16.40.20", - "ttl": 32 - }, - "outer_l4": { - "dstport": "1234", - "srcport": "2001" - }, - "traffic_type": "continuous" - } - } - - ixnet = mock.MagicMock() - ixnet.remapIds.return_value = ["0"] - ixnet.setMultiAttribute.return_value = [1] - ixnet.commit.return_value = [1] - ixnet.getList.side_effect = [[1], [0, 1], [0], ["srcIp", "dstIp"]] - - ixnet_gen = IxNextgen(ixnet) - - result = ixnet_gen.add_ip_header(static_traffic_params, IP_VERSION_4) - self.assertIsNone(result) - self.assertGreater(ixnet.setMultiAttribute.call_count, 0) - self.assertEqual(ixnet.commit.call_count, 1) - - def test_add_ip_header_v6(self): - static_traffic_profile = { - "uplink_0": { - "id": 1, - "bidir": "False", - "duration": 60, - "iload": "100", - "outer_l2": { - "dstmac": "00:00:00:00:00:03", - "framesPerSecond": True, - "framesize": {"64B": "100"}, - "srcmac": "00:00:00:00:00:01" - }, - "outer_l3": { - "count": 1024, - "dscp": 0, - "dstip4": "152.16.40.20", - "proto": "udp", - "srcip4": "152.16.100.20", - "ttl": 32 - }, - "outer_l3v6": { - "count": 1024, - "dscp": 0, - "dstip4": "152.16.100.20", - "proto": "udp", - "srcip4": "152.16.40.20", - "ttl": 32 - }, - "outer_l4": { - "dstport": "2001", - "srcport": "1234" - }, - "traffic_type": "continuous" - }, - "downlink_0": { - "id": 2, - "bidir": "False", - "duration": 60, - "iload": "100", - "outer_l2": { - "dstmac": "00:00:00:00:00:04", - "framesPerSecond": True, - "framesize": {"64B": "100"}, - "srcmac": "00:00:00:00:00:01" - }, - "outer_l3": { - "count": 1024, - "dscp": 0, - "dstip4": "152.16.100.20", - "proto": "udp", - "srcip4": "152.16.40.20", - "ttl": 32 - }, - "outer_l3v6": { - "count": 1024, - "dscp": 0, - "dstip4": "152.16.100.20", - "proto": "udp", - "srcip4": "152.16.40.20", - "ttl": 32 - }, - "outer_l4": { - "dstport": "1234", - "srcport": "2001" - }, - "traffic_type": "continuous" - } - } - - ixnet = mock.MagicMock() - ixnet.getList.side_effect = [[1], [1], [1], ["srcIp", "dstIp"]] - ixnet.remapIds.return_value = ["0"] - ixnet.setMultiAttribute.return_value = [1] - ixnet.commit.return_value = [1] - - ixnet_gen = IxNextgen(ixnet) - - result = ixnet_gen.add_ip_header(static_traffic_profile, IP_VERSION_6) - self.assertIsNone(result) - self.assertGreater(ixnet.setMultiAttribute.call_count, 0) - self.assertEqual(ixnet.commit.call_count, 1) - - def test_add_ip_header_v6_nothing_to_do(self): - static_traffic_params = { - "uplink_0": { - "id": 1, - "bidir": "False", - "duration": 60, - "iload": "100", - "outer_l2": { - "dstmac": "00:00:00:00:00:03", - "framesPerSecond": True, - "framesize": {"64B": "100"}, - "srcmac": "00:00:00:00:00:01" - }, - "outer_l3": { - "dscp": 0, - "dstip4": "152.16.40.20", - "proto": "udp", - "srcip4": "152.16.100.20", - "count": 1024, - "ttl": 32 - }, - "outer_l3v6": { - "dscp": 0, - "dstip4": "152.16.40.20", - "proto": "udp", - "srcip4": "152.16.100.20", - "ttl": 32 - }, - "outer_l4": { - "dstport": "2001", - "srcport": "1234" - }, - "traffic_type": "continuous" - }, - "downlink_0": { - "id": 2, - "bidir": "False", - "duration": 60, - "iload": "100", - "outer_l2": { - "dstmac": "00:00:00:00:00:04", - "framesPerSecond": True, - "framesize": {"64B": "100"}, - "srcmac": "00:00:00:00:00:01" - }, - "outer_l3": { - "count": 1024, - "dscp": 0, - "dstip4": "152.16.100.20", - "proto": "udp", - "srcip4": "152.16.40.20", - "ttl": 32 - }, - "outer_l3v6": { - "count": 1024, - "dscp": 0, - "dstip4": "152.16.100.20", - "proto": "udp", - "srcip4": "152.16.40.20", - "ttl": 32 - }, - "outer_l4": { - "dstport": "1234", - "srcport": "2001" - }, - "traffic_type": "continuous" - } - } - - ixnet = mock.MagicMock() - ixnet.getList.side_effect = [[1], [0, 1], [1], ["srcIP", "dstIP"]] - ixnet.remapIds.return_value = ["0"] - ixnet.setMultiAttribute.return_value = [1] - ixnet.commit.return_value = [1] - - ixnet_gen = IxNextgen(ixnet) - - result = ixnet_gen.add_ip_header(static_traffic_params, IP_VERSION_6) - self.assertIsNone(result) - self.assertEqual(ixnet.setMultiAttribute.call_count, 0) - - def test_set_random_ip_multi_attributes_bad_ip_version(self): - bad_ip_version = object() - ixnet_gen = IxNextgen(mock.Mock()) - with self.assertRaises(ValueError): - ixnet_gen.set_random_ip_multi_attributes( - mock.Mock(), bad_ip_version, mock.Mock(), mock.Mock()) - - def test_get_config(self): - tg_cfg = { - "vdu": [ - { - "external-interface": [ - { - "virtual-interface": { - "vpci": "0000:07:00.1", - }, - }, - { - "virtual-interface": { - "vpci": "0001:08:01.2", - }, - }, - ], - }, - ], - "mgmt-interface": { - "ip": "test1", - "tg-config": { - "dut_result_dir": "test2", - "version": "test3", - "ixchassis": "test4", - "tcl_port": "test5", - }, - } - } - - expected = { - 'machine': 'test1', - 'port': 'test5', - 'chassis': 'test4', - 'cards': ['0000', '0001'], - 'ports': ['07', '08'], - 'output_dir': 'test2', - 'version': 'test3', - 'bidir': True, - } - - result = IxNextgen.get_config(tg_cfg) - self.assertDictEqual(result, expected) - - def test_ix_update_ether(self): - static_traffic_params = { - "uplink_0": { - "id": 1, - "bidir": "False", - "duration": 60, - "iload": "100", - "outer_l2": { - "dstmac": "00:00:00:00:00:03", - "framesPerSecond": True, - "framesize": 64, - "srcmac": "00:00:00:00:00:01" - }, - "outer_l3": { - "dscp": 0, - "dstip4": "152.16.40.20", - "proto": "udp", - "srcip4": "152.16.100.20", - "ttl": 32 - }, - "outer_l3v4": { - "dscp": 0, - "dstip4": "152.16.40.20", - "proto": "udp", - "srcip4": "152.16.100.20", - "ttl": 32 - }, - "outer_l3v6": { - "count": 1024, - "dscp": 0, - "dstip4": "152.16.100.20", - "proto": "udp", - "srcip4": "152.16.40.20", - "ttl": 32 - }, - "outer_l4": { - "dstport": "2001", - "srcport": "1234" - }, - "traffic_type": "continuous" - }, - "downlink_0": { - "id": 2, - "bidir": "False", - "duration": 60, - "iload": "100", - "outer_l2": { - "dstmac": "00:00:00:00:00:04", - "framesPerSecond": True, - "framesize": 64, - "srcmac": "00:00:00:00:00:01" - }, - "outer_l3": { - "count": 1024, - "dscp": 0, - "dstip4": "152.16.100.20", - "proto": "udp", - "srcip4": "152.16.40.20", - "ttl": 32 - }, - "outer_l3v4": { - "count": 1024, - "dscp": 0, - "dstip4": "152.16.100.20", - "proto": "udp", - "srcip4": "152.16.40.20", - "ttl": 32 - }, - "outer_l3v6": { - "count": 1024, - "dscp": 0, - "dstip4": "152.16.100.20", - "proto": "udp", - "srcip4": "152.16.40.20", - "ttl": 32 - }, - "outer_l4": { - "dstport": "1234", - "srcport": "2001" - }, - "traffic_type": "continuous" - } - } - - ixnet = mock.MagicMock() - ixnet.setMultiAttribute.return_value = [1] - ixnet.commit.return_value = [1] - ixnet.getList.side_effect = [ - [1], - [1], - [1], - [ - "ethernet.header.destinationAddress", - "ethernet.header.sourceAddress", - ], - ] - - ixnet_gen = IxNextgen(ixnet) - - result = ixnet_gen.ix_update_ether(static_traffic_params) - self.assertIsNone(result) - self.assertGreater(ixnet.setMultiAttribute.call_count, 0) - - def test_ix_update_ether_nothing_to_do(self): - static_traffic_params = { - "uplink_0": { - "id": 1, - "bidir": "False", - "duration": 60, - "iload": "100", - "outer_l3": { - "dscp": 0, - "dstip4": "152.16.40.20", - "proto": "udp", - "srcip4": "152.16.100.20", - "ttl": 32 - }, - "outer_l3v4": { - "dscp": 0, - "dstip4": "152.16.40.20", - "proto": "udp", - "srcip4": "152.16.100.20", - "ttl": 32 - }, - "outer_l3v6": { - "count": 1024, - "dscp": 0, - "dstip4": "152.16.100.20", - "proto": "udp", - "srcip4": "152.16.40.20", - "ttl": 32 - }, - "outer_l4": { - "dstport": "2001", - "srcport": "1234" - }, - "traffic_type": "continuous" - }, - "downlink_0": { - "id": 2, - "bidir": "False", - "duration": 60, - "iload": "100", - "outer_l3": { - "count": 1024, - "dscp": 0, - "dstip4": "152.16.100.20", - "proto": "udp", - "srcip4": "152.16.40.20", - "ttl": 32 - }, - "outer_l3v4": { - "count": 1024, - "dscp": 0, - "dstip4": "152.16.100.20", - "proto": "udp", - "srcip4": "152.16.40.20", - "ttl": 32 - }, - "outer_l3v6": { - "count": 1024, - "dscp": 0, - "dstip4": "152.16.100.20", - "proto": "udp", - "srcip4": "152.16.40.20", - "ttl": 32 - }, - "outer_l4": { - "dstport": "1234", - "srcport": "2001" - }, - "traffic_type": "continuous" - } - } - - ixnet = mock.MagicMock() - ixnet.setMultiAttribute.return_value = [1] - ixnet.commit.return_value = [1] - ixnet.getList.side_effect = [ - [1], - [1], - [1], - [ - "ethernet.header.destinationAddress", - "ethernet.header.sourceAddress", - ], - ] - - ixnet_gen = IxNextgen(ixnet) - - result = ixnet_gen.ix_update_ether(static_traffic_params) - self.assertIsNone(result) - self.assertEqual(ixnet.setMultiAttribute.call_count, 0) diff --git a/yardstick/tests/unit/network_services/libs/ixia_libs/test_ixnet_api.py b/yardstick/tests/unit/network_services/libs/ixia_libs/test_ixnet_api.py new file mode 100644 index 000000000..2416aee61 --- /dev/null +++ b/yardstick/tests/unit/network_services/libs/ixia_libs/test_ixnet_api.py @@ -0,0 +1,480 @@ +# Copyright (c) 2018 Intel Corporation +# +# 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. + +import mock +import IxNetwork +import unittest + +from yardstick.common import exceptions +from yardstick.network_services.libs.ixia_libs.ixnet import ixnet_api + + +UPLINK = 'uplink' +DOWNLINK = 'downlink' + +TRAFFIC_PARAMETERS = { + UPLINK: { + 'id': 1, + 'bidir': 'False', + 'duration': 60, + 'rate': 10000.5, + 'rate_unit': 'fps', + 'outer_l2': { + 'framesize': {'64B': '25', '256B': '75'} + }, + 'outer_l3': { + 'count': 512, + 'seed': 1, + 'dscp': 0, + 'proto': 'udp', + 'ttl': 32, + 'dstip': '152.16.40.20', + 'srcip': '152.16.100.20', + 'dstmask': 24, + 'srcmask': 24 + }, + 'outer_l4': { + 'seed': 1, + 'count': 1, + 'dstport': 2001, + 'srcport': 1234, + 'srcportmask': 0, + 'dstportmask': 0 + }, + 'traffic_type': 'continuous' + }, + DOWNLINK: { + 'id': 2, + 'bidir': 'False', + 'duration': 60, + 'rate': 75.2, + 'rate_unit': '%', + 'outer_l2': { + 'framesize': {'128B': '35', '1024B': '65'} + }, + 'outer_l3': { + 'count': 1024, + 'seed': 1, + 'dscp': 0, + 'proto': 'udp', + 'ttl': 32, + 'dstip': '2001::10', + 'srcip': '2021::10', + 'dstmask': 64, + 'srcmask': 64 + }, + 'outer_l4': { + 'seed': 1, + 'count': 1, + 'dstport': 1234, + 'srcport': 2001, + 'srcportmask': 0, + 'dstportmask': 0 + }, + 'traffic_type': 'continuous' + } +} + + +class TestIxNextgen(unittest.TestCase): + + def setUp(self): + self.ixnet = mock.Mock() + self.ixnet.execute = mock.Mock() + self.ixnet.getRoot.return_value = 'my_root' + self.ixnet_gen = ixnet_api.IxNextgen() + self.ixnet_gen._ixnet = self.ixnet + + def test_get_config(self): + tg_cfg = { + 'vdu': [ + { + 'external-interface': [ + {'virtual-interface': {'vpci': '0000:07:00.1'}}, + {'virtual-interface': {'vpci': '0001:08:01.2'}} + ] + }, + ], + 'mgmt-interface': { + 'ip': 'test1', + 'tg-config': { + 'dut_result_dir': 'test2', + 'version': 'test3', + 'ixchassis': 'test4', + 'tcl_port': 'test5', + }, + } + } + + expected = { + 'machine': 'test1', + 'port': 'test5', + 'chassis': 'test4', + 'cards': ['0000', '0001'], + 'ports': ['07', '08'], + 'output_dir': 'test2', + 'version': 'test3', + 'bidir': True, + } + + result = ixnet_api.IxNextgen.get_config(tg_cfg) + self.assertEqual(result, expected) + + def test__get_config_element_by_flow_group_name(self): + self.ixnet_gen._ixnet.getList.side_effect = [['traffic_item'], + ['fg_01']] + self.ixnet_gen._ixnet.getAttribute.return_value = 'flow_group_01' + output = self.ixnet_gen._get_config_element_by_flow_group_name( + 'flow_group_01') + self.assertEqual('traffic_item/configElement:flow_group_01', output) + + def test__get_config_element_by_flow_group_name_no_match(self): + self.ixnet_gen._ixnet.getList.side_effect = [['traffic_item'], + ['fg_01']] + self.ixnet_gen._ixnet.getAttribute.return_value = 'flow_group_02' + output = self.ixnet_gen._get_config_element_by_flow_group_name( + 'flow_group_01') + self.assertIsNone(output) + + def test__get_stack_item(self): + self.ixnet_gen._ixnet.getList.return_value = ['tcp1', 'tcp2', 'udp'] + with mock.patch.object( + self.ixnet_gen, '_get_config_element_by_flow_group_name') as \ + mock_get_cfg_element: + mock_get_cfg_element.return_value = 'cfg_element' + output = self.ixnet_gen._get_stack_item(mock.ANY, ixnet_api.PROTO_TCP) + self.assertEqual(['tcp1', 'tcp2'], output) + + def test__get_stack_item_no_config_element(self): + with mock.patch.object( + self.ixnet_gen, '_get_config_element_by_flow_group_name', + return_value=None): + with self.assertRaises(exceptions.IxNetworkFlowNotPresent): + self.ixnet_gen._get_stack_item(mock.ANY, mock.ANY) + + def test__get_field_in_stack_item(self): + self.ixnet_gen._ixnet.getList.return_value = ['field1', 'field2'] + output = self.ixnet_gen._get_field_in_stack_item(mock.ANY, 'field2') + self.assertEqual('field2', output) + + def test__get_field_in_stack_item_no_field_present(self): + self.ixnet_gen._ixnet.getList.return_value = ['field1', 'field2'] + with self.assertRaises(exceptions.IxNetworkFieldNotPresentInStackItem): + self.ixnet_gen._get_field_in_stack_item(mock.ANY, 'field3') + + def test__parse_framesize(self): + framesize = {'64B': '75', '512b': '25'} + output = self.ixnet_gen._parse_framesize(framesize) + self.assertEqual(2, len(output)) + self.assertIn([64, 64, 75], output) + self.assertIn([512, 512, 25], output) + + @mock.patch.object(IxNetwork, 'IxNet') + def test_connect(self, mock_ixnet): + mock_ixnet.return_value = self.ixnet + with mock.patch.object(self.ixnet_gen, 'get_config') as mock_config: + mock_config.return_value = {'machine': 'machine_fake', + 'port': 'port_fake', + 'version': 12345} + self.ixnet_gen.connect(mock.ANY) + + self.ixnet.connect.assert_called_once_with( + 'machine_fake', '-port', 'port_fake', '-version', '12345') + mock_config.assert_called_once() + + def test_connect_invalid_config_no_machine(self): + self.ixnet_gen.get_config = mock.Mock(return_value={ + 'port': 'port_fake', + 'version': '12345'}) + self.assertRaises(KeyError, self.ixnet_gen.connect, mock.ANY) + self.ixnet.connect.assert_not_called() + + def test_connect_invalid_config_no_port(self): + self.ixnet_gen.get_config = mock.Mock(return_value={ + 'machine': 'machine_fake', + 'version': '12345'}) + self.assertRaises(KeyError, self.ixnet_gen.connect, mock.ANY) + self.ixnet.connect.assert_not_called() + + def test_connect_invalid_config_no_version(self): + self.ixnet_gen.get_config = mock.Mock(return_value={ + 'machine': 'machine_fake', + 'port': 'port_fake'}) + self.assertRaises(KeyError, self.ixnet_gen.connect, mock.ANY) + self.ixnet.connect.assert_not_called() + + def test_connect_no_config(self): + self.ixnet_gen.get_config = mock.Mock(return_value={}) + self.assertRaises(KeyError, self.ixnet_gen.connect, mock.ANY) + self.ixnet.connect.assert_not_called() + + def test_clear_config(self): + self.ixnet_gen.clear_config() + self.ixnet.execute.assert_called_once_with('newConfig') + + @mock.patch.object(ixnet_api, 'log') + def test_assign_ports_2_ports(self, *args): + self.ixnet.getAttribute.side_effect = ['up', 'down'] + config = { + 'chassis': '1.1.1.1', + 'cards': ['1', '2'], + 'ports': ['2', '2']} + self.ixnet_gen._cfg = config + + self.assertIsNone(self.ixnet_gen.assign_ports()) + self.assertEqual(self.ixnet.execute.call_count, 2) + self.assertEqual(self.ixnet.commit.call_count, 4) + self.assertEqual(self.ixnet.getAttribute.call_count, 2) + + @mock.patch.object(ixnet_api, 'log') + def test_assign_ports_port_down(self, mock_log): + self.ixnet.getAttribute.return_value = 'down' + config = { + 'chassis': '1.1.1.1', + 'cards': ['1', '2'], + 'ports': ['3', '4']} + self.ixnet_gen._cfg = config + self.ixnet_gen.assign_ports() + mock_log.warning.assert_called() + + def test_assign_ports_no_config(self): + self.ixnet_gen._cfg = {} + self.assertRaises(KeyError, self.ixnet_gen.assign_ports) + + def test__create_traffic_item(self): + self.ixnet.add.return_value = 'my_new_traffic_item' + self.ixnet.remapIds.return_value = ['my_traffic_item_id'] + + self.ixnet_gen._create_traffic_item() + self.ixnet.add.assert_called_once_with( + 'my_root/traffic', 'trafficItem') + self.ixnet.setMultiAttribute.assert_called_once_with( + 'my_new_traffic_item', '-name', 'RFC2544', '-trafficType', 'raw') + self.assertEqual(2, self.ixnet.commit.call_count) + self.ixnet.remapIds.assert_called_once_with('my_new_traffic_item') + self.ixnet.setAttribute('my_traffic_item_id/tracking', + '-trackBy', 'trafficGroupId0') + + def test__create_flow_groups(self): + self.ixnet_gen.ixnet.getList.side_effect = [['traffic_item'], ['1', '2']] + self.ixnet_gen.ixnet.add.side_effect = ['endp1', 'endp2'] + self.ixnet_gen._create_flow_groups() + self.ixnet_gen.ixnet.add.assert_has_calls([ + mock.call('traffic_item', 'endpointSet'), + mock.call('traffic_item', 'endpointSet')]) + self.ixnet_gen.ixnet.setMultiAttribute.assert_has_calls([ + mock.call('endp1', '-name', '1', '-sources', ['1/protocols'], + '-destinations', ['2/protocols']), + mock.call('endp2', '-name', '2', '-sources', ['2/protocols'], + '-destinations', ['1/protocols'])]) + + def test__append_protocol_to_stack(self): + + self.ixnet_gen._append_procotol_to_stack('my_protocol', 'prev_element') + self.ixnet.execute.assert_called_with( + 'append', 'prev_element', + 'my_root/traffic/protocolTemplate:"my_protocol"') + + def test__setup_config_elements(self): + self.ixnet_gen.ixnet.getList.side_effect = [['traffic_item'], + ['cfg_element']] + with mock.patch.object(self.ixnet_gen, '_append_procotol_to_stack') as \ + mock_append_proto: + self.ixnet_gen._setup_config_elements() + mock_append_proto.assert_has_calls([ + mock.call(ixnet_api.PROTO_UDP, 'cfg_element/stack:"ethernet-1"'), + mock.call(ixnet_api.PROTO_IPV4, 'cfg_element/stack:"ethernet-1"')]) + self.ixnet_gen.ixnet.setAttribute.assert_has_calls([ + mock.call('cfg_element/frameRateDistribution', '-portDistribution', + 'splitRateEvenly'), + mock.call('cfg_element/frameRateDistribution', + '-streamDistribution', 'splitRateEvenly')]) + + @mock.patch.object(ixnet_api.IxNextgen, '_create_traffic_item') + @mock.patch.object(ixnet_api.IxNextgen, '_create_flow_groups') + @mock.patch.object(ixnet_api.IxNextgen, '_setup_config_elements') + def test_create_traffic_model(self, mock__setup_config_elements, + mock__create_flow_groups, + mock__create_traffic_item): + + self.ixnet_gen.create_traffic_model() + mock__create_traffic_item.assert_called_once() + mock__create_flow_groups.assert_called_once() + mock__setup_config_elements.assert_called_once() + + def test__update_frame_mac(self): + with mock.patch.object(self.ixnet_gen, '_get_field_in_stack_item') as \ + mock_get_field: + mock_get_field.return_value = 'field_descriptor' + self.ixnet_gen._update_frame_mac('ethernet_descriptor', 'field', 'mac') + mock_get_field.assert_called_once_with('ethernet_descriptor', 'field') + self.ixnet_gen.ixnet.setMultiAttribute( + 'field_descriptor', '-singleValue', 'mac', '-fieldValue', 'mac', + '-valueType', 'singleValue') + self.ixnet_gen.ixnet.commit.assert_called_once() + + def test_update_frame(self): + with mock.patch.object( + self.ixnet_gen, '_get_config_element_by_flow_group_name', + return_value='cfg_element'), \ + mock.patch.object(self.ixnet_gen, '_update_frame_mac') as \ + mock_update_frame, \ + mock.patch.object(self.ixnet_gen, '_get_stack_item') as \ + mock_get_stack_item: + mock_get_stack_item.side_effect = [['item1'], ['item2'], + ['item3'], ['item4']] + self.ixnet_gen.update_frame(TRAFFIC_PARAMETERS, 50) + + self.assertEqual(6, len(self.ixnet_gen.ixnet.setMultiAttribute.mock_calls)) + self.assertEqual(4, len(mock_update_frame.mock_calls)) + + def test_update_frame_flow_not_present(self): + with mock.patch.object( + self.ixnet_gen, '_get_config_element_by_flow_group_name', + return_value=None): + with self.assertRaises(exceptions.IxNetworkFlowNotPresent): + self.ixnet_gen.update_frame(TRAFFIC_PARAMETERS, 40) + + def test_get_statistics(self): + port_statistics = '::ixNet::OBJ-/statistics/view:"Port Statistics"' + flow_statistics = '::ixNet::OBJ-/statistics/view:"Flow Statistics"' + with mock.patch.object(self.ixnet_gen, '_build_stats_map') as \ + mock_build_stats: + self.ixnet_gen.get_statistics() + + mock_build_stats.assert_has_calls([ + mock.call(port_statistics, self.ixnet_gen.PORT_STATS_NAME_MAP), + mock.call(flow_statistics, self.ixnet_gen.LATENCY_NAME_MAP)]) + + def test__update_ipv4_address(self): + with mock.patch.object(self.ixnet_gen, '_get_field_in_stack_item', + return_value='field_desc'): + self.ixnet_gen._update_ipv4_address(mock.ANY, mock.ANY, '192.168.1.1', + 100, 26, 25) + self.ixnet_gen.ixnet.setMultiAttribute.assert_called_once_with( + 'field_desc', '-seed', 100, '-fixedBits', '192.168.1.1', + '-randomMask', '0.0.0.63', '-valueType', 'random', + '-countValue', 25) + + def test__update_udp_port(self): + with mock.patch.object(self.ixnet_gen, '_get_field_in_stack_item', + return_value='field_desc'): + self.ixnet_gen._update_udp_port(mock.ANY, mock.ANY, 1234, + 2, 0, 2) + + self.ixnet_gen.ixnet.setMultiAttribute.assert_called_once_with( + 'field_desc', + '-auto', 'false', + '-seed', 1, + '-fixedBits', 1234, + '-randomMask', 0, + '-valueType', 'random', + '-countValue', 1) + + def test_update_ip_packet(self): + with mock.patch.object(self.ixnet_gen, '_update_ipv4_address') as \ + mock_update_add, \ + mock.patch.object(self.ixnet_gen, '_get_stack_item'), \ + mock.patch.object(self.ixnet_gen, + '_get_config_element_by_flow_group_name', return_value='celm'): + self.ixnet_gen.update_ip_packet(TRAFFIC_PARAMETERS) + + self.assertEqual(4, len(mock_update_add.mock_calls)) + + def test_update_ip_packet_exception_no_config_element(self): + with mock.patch.object(self.ixnet_gen, + '_get_config_element_by_flow_group_name', + return_value=None): + with self.assertRaises(exceptions.IxNetworkFlowNotPresent): + self.ixnet_gen.update_ip_packet(TRAFFIC_PARAMETERS) + + def test_update_l4(self): + with mock.patch.object(self.ixnet_gen, '_update_udp_port') as \ + mock_update_udp, \ + mock.patch.object(self.ixnet_gen, '_get_stack_item'), \ + mock.patch.object(self.ixnet_gen, + '_get_config_element_by_flow_group_name', return_value='celm'): + self.ixnet_gen.update_l4(TRAFFIC_PARAMETERS) + + self.assertEqual(4, len(mock_update_udp.mock_calls)) + + def test_update_l4_exception_no_config_element(self): + with mock.patch.object(self.ixnet_gen, + '_get_config_element_by_flow_group_name', + return_value=None): + with self.assertRaises(exceptions.IxNetworkFlowNotPresent): + self.ixnet_gen.update_l4(TRAFFIC_PARAMETERS) + + def test_update_l4_exception_no_supported_proto(self): + traffic_parameters = { + UPLINK: { + 'id': 1, + 'outer_l3': { + 'proto': 'unsupported', + }, + }, + } + with mock.patch.object(self.ixnet_gen, + '_get_config_element_by_flow_group_name', + return_value='celm'): + with self.assertRaises(exceptions.IXIAUnsupportedProtocol): + self.ixnet_gen.update_l4(traffic_parameters) + + @mock.patch.object(ixnet_api.IxNextgen, '_get_traffic_state') + def test_start_traffic(self, mock_ixnextgen_get_traffic_state): + self.ixnet_gen._ixnet.getList.return_value = [0] + + mock_ixnextgen_get_traffic_state.side_effect = [ + 'stopped', 'started', 'started', 'started'] + + result = self.ixnet_gen.start_traffic() + self.assertIsNone(result) + self.ixnet.getList.assert_called_once() + self.assertEqual(3, self.ixnet_gen._ixnet.execute.call_count) + + @mock.patch.object(ixnet_api.IxNextgen, '_get_traffic_state') + def test_start_traffic_traffic_running( + self, mock_ixnextgen_get_traffic_state): + self.ixnet_gen._ixnet.getList.return_value = [0] + mock_ixnextgen_get_traffic_state.side_effect = [ + 'started', 'stopped', 'started'] + + result = self.ixnet_gen.start_traffic() + self.assertIsNone(result) + self.ixnet.getList.assert_called_once() + self.assertEqual(4, self.ixnet_gen._ixnet.execute.call_count) + + @mock.patch.object(ixnet_api.IxNextgen, '_get_traffic_state') + def test_start_traffic_wait_for_traffic_to_stop( + self, mock_ixnextgen_get_traffic_state): + self.ixnet_gen._ixnet.getList.return_value = [0] + mock_ixnextgen_get_traffic_state.side_effect = [ + 'started', 'started', 'started', 'stopped', 'started'] + + result = self.ixnet_gen.start_traffic() + self.assertIsNone(result) + self.ixnet.getList.assert_called_once() + self.assertEqual(4, self.ixnet_gen._ixnet.execute.call_count) + + @mock.patch.object(ixnet_api.IxNextgen, '_get_traffic_state') + def test_start_traffic_wait_for_traffic_start( + self, mock_ixnextgen_get_traffic_state): + self.ixnet_gen._ixnet.getList.return_value = [0] + mock_ixnextgen_get_traffic_state.side_effect = [ + 'stopped', 'stopped', 'stopped', 'started'] + + result = self.ixnet_gen.start_traffic() + self.assertIsNone(result) + self.ixnet.getList.assert_called_once() + self.assertEqual(3, self.ixnet_gen._ixnet.execute.call_count) diff --git a/yardstick/tests/unit/network_services/nfvi/test_resource.py b/yardstick/tests/unit/network_services/nfvi/test_resource.py index 9f337c673..c06658218 100644 --- a/yardstick/tests/unit/network_services/nfvi/test_resource.py +++ b/yardstick/tests/unit/network_services/nfvi/test_resource.py @@ -17,10 +17,11 @@ import errno import mock import unittest +from yardstick.common import exceptions +from yardstick.common.exceptions import ResourceCommandError from yardstick.network_services.nfvi.resource import ResourceProfile from yardstick.network_services.nfvi import resource, collectd -from yardstick.common.exceptions import ResourceCommandError -from yardstick import ssh + class TestResourceProfile(unittest.TestCase): VNFD = {'vnfd:vnfd-catalog': @@ -134,25 +135,45 @@ class TestResourceProfile(unittest.TestCase): self.assertIsNone(self.resource_profile._start_collectd(ssh_mock, "/opt/nsb_bin")) - ssh_mock.execute = mock.Mock(side_effect=ssh.SSHError) - with self.assertRaises(ssh.SSHError): + ssh_mock.execute = mock.Mock(side_effect=exceptions.SSHError) + with self.assertRaises(exceptions.SSHError): self.resource_profile._start_collectd(ssh_mock, "/opt/nsb_bin") ssh_mock.execute = mock.Mock(return_value=(1, "", "")) - self.assertIsNone(self.resource_profile._start_collectd(ssh_mock, - "/opt/nsb_bin")) + with self.assertRaises(ResourceCommandError): + self.resource_profile._start_collectd(ssh_mock, "/opt/nsb_bin") + + def test__reset_rabbitmq(self): + ssh_mock = mock.Mock() + ssh_mock.execute = mock.Mock(return_value=(1, "", "")) + with self.assertRaises(exceptions.ResourceCommandError): + self.resource_profile._reset_rabbitmq(ssh_mock) + + def test__check_rabbitmq_user(self): + ssh_mock = mock.Mock() + ssh_mock.execute = mock.Mock(return_value=(0, "title\nadmin\t[]", "")) + self.assertTrue(self.resource_profile._check_rabbitmq_user(ssh_mock)) + + def test__set_rabbitmq_admin_user(self): + ssh_mock = mock.Mock() + ssh_mock.execute = mock.Mock(return_value=(1, "", "")) + with self.assertRaises(exceptions.ResourceCommandError): + self.resource_profile._set_rabbitmq_admin_user(ssh_mock) def test__start_rabbitmq(self): ssh_mock = mock.Mock() - ssh_mock.execute = mock.Mock(return_value=(0, "RabbitMQ", "")) - self.assertIsNone(self.resource_profile._start_rabbitmq(ssh_mock)) + self.resource_profile._reset_rabbitmq = mock.Mock() + self.resource_profile._set_rabbitmq_admin_user = mock.Mock() - ssh_mock.execute = mock.Mock(return_value=(0, "", "")) - with self.assertRaises(ResourceCommandError): + self.resource_profile._reset_mq_flag = True + ssh_mock.execute = mock.Mock(return_value=(1, "", "")) + with self.assertRaises(exceptions.ResourceCommandError): self.resource_profile._start_rabbitmq(ssh_mock) + self.resource_profile._reset_mq_flag = False + self.resource_profile._check_rabbitmq_user = mock.Mock(return_value=False) ssh_mock.execute = mock.Mock(return_value=(1, "", "")) - with self.assertRaises(ResourceCommandError): + with self.assertRaises(exceptions.ResourceCommandError): self.resource_profile._start_rabbitmq(ssh_mock) def test__prepare_collectd_conf(self): diff --git a/yardstick/tests/unit/network_services/test_yang_model.py b/yardstick/tests/unit/network_services/test_yang_model.py deleted file mode 100644 index a7eb36b8a..000000000 --- a/yardstick/tests/unit/network_services/test_yang_model.py +++ /dev/null @@ -1,129 +0,0 @@ -# Copyright (c) 2016-2017 Intel Corporation -# -# 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. -# - -import mock -import unittest - -from yardstick.network_services.yang_model import YangModel - - -class YangModelTestCase(unittest.TestCase): - """Test all Yang Model methods.""" - - ENTRIES = { - 'access-list1': { - 'acl': { - 'access-list-entries': [{ - 'ace': { - 'ace-oper-data': { - 'match-counter': 0}, - 'actions': 'drop,count', - 'matches': { - 'destination-ipv4-network': - '152.16.40.20/24', - 'destination-port-range': { - 'lower-port': 0, - 'upper-port': 65535}, - 'source-ipv4-network': '0.0.0.0/0', - 'source-port-range': { - 'lower-port': 0, - 'upper-port': 65535}}, - 'rule-name': 'rule1588'}}, - { - 'ace': { - 'ace-oper-data': { - 'match-counter': 0}, - 'actions': 'drop,count', - 'matches': { - 'destination-ipv4-network': - '0.0.0.0/0', - 'destination-port-range': { - 'lower-port': 0, - 'upper-port': 65535}, - 'source-ipv4-network': - '152.16.100.20/24', - 'source-port-range': { - 'lower-port': 0, - 'upper-port': 65535}}, - 'rule-name': 'rule1589'}}], - 'acl-name': 'sample-ipv4-acl', - 'acl-type': 'ipv4-acl'} - } - } - - def test__init__(self): - cfg = "yang.yaml" - y = YangModel(cfg) - self.assertEqual(y.config_file, cfg) - - def test_config_file_setter(self): - cfg = "yang.yaml" - y = YangModel(cfg) - self.assertEqual(y.config_file, cfg) - cfg2 = "yang2.yaml" - y.config_file = cfg2 - self.assertEqual(y.config_file, cfg2) - - def test__get_entries(self): - cfg = "yang.yaml" - y = YangModel(cfg) - y._options = self.ENTRIES - y._get_entries() - self.assertIn("p acl add", y._rules) - - def test__get_entries_no_options(self): - cfg = "yang.yaml" - y = YangModel(cfg) - y._get_entries() - self.assertEqual(y._rules, '') - - @mock.patch('yardstick.network_services.yang_model.open') - @mock.patch('yardstick.network_services.yang_model.yaml_load') - def test__read_config(self, mock_safe_load, *args): - cfg = "yang.yaml" - y = YangModel(cfg) - mock_safe_load.return_value = expected = {'key1': 'value1', 'key2': 'value2'} - y._read_config() - self.assertDictEqual(y._options, expected) - - @mock.patch('yardstick.network_services.yang_model.open') - def test__read_config_open_error(self, mock_open): - cfg = "yang.yaml" - y = YangModel(cfg) - mock_open.side_effect = IOError('my error') - - self.assertEqual(y._options, {}) - with self.assertRaises(IOError) as raised: - y._read_config() - - self.assertIn('my error', str(raised.exception)) - self.assertEqual(y._options, {}) - - def test_get_rules(self): - cfg = "yang.yaml" - y = YangModel(cfg) - y._read_config = read_mock = mock.Mock() - y._get_entries = get_mock = mock.Mock() - - y._rules = None - self.assertIsNone(y.get_rules()) - self.assertEqual(read_mock.call_count, 1) - self.assertEqual(get_mock.call_count, 1) - - # True value should prevent calling read and get - y._rules = 999 - self.assertEqual(y.get_rules(), 999) - self.assertEqual(read_mock.call_count, 1) - self.assertEqual(get_mock.call_count, 1) diff --git a/yardstick/tests/unit/network_services/traffic_profile/test_base.py b/yardstick/tests/unit/network_services/traffic_profile/test_base.py index 3b8804976..0dc3e0579 100644 --- a/yardstick/tests/unit/network_services/traffic_profile/test_base.py +++ b/yardstick/tests/unit/network_services/traffic_profile/test_base.py @@ -44,7 +44,7 @@ class TestTrafficProfile(unittest.TestCase): traffic_profile = base.TrafficProfile(self.TRAFFIC_PROFILE) self.assertEqual(self.TRAFFIC_PROFILE, traffic_profile.params) - def test_execute(self): + def test_execute_traffic(self): traffic_profile = base.TrafficProfile(self.TRAFFIC_PROFILE) self.assertRaises(NotImplementedError, traffic_profile.execute_traffic, {}) @@ -69,5 +69,44 @@ class TestTrafficProfile(unittest.TestCase): class TestDummyProfile(unittest.TestCase): def test_execute(self): - dummy_profile = base.DummyProfile(base.TrafficProfile) + tp_config = {'traffic_profile': {'duration': 15}} + dummy_profile = base.DummyProfile(tp_config) self.assertIsNone(dummy_profile.execute({})) + + +class TrafficProfileConfigTestCase(unittest.TestCase): + + def test__init(self): + tp_config = {'traffic_profile': {'packet_sizes': {'64B': 100}}} + tp_config_obj = base.TrafficProfileConfig(tp_config) + self.assertEqual({'64B': 100}, tp_config_obj.packet_sizes) + self.assertEqual(base.TrafficProfileConfig.DEFAULT_DURATION, + tp_config_obj.duration) + + def test__init_set_duration(self): + tp_config = {'traffic_profile': {'duration': 15}} + tp_config_obj = base.TrafficProfileConfig(tp_config) + self.assertEqual(base.TrafficProfileConfig.DEFAULT_SCHEMA, + tp_config_obj.schema) + self.assertEqual(float(base.TrafficProfileConfig.DEFAULT_FRAME_RATE), + tp_config_obj.frame_rate) + self.assertEqual(15, tp_config_obj.duration) + + def test__parse_rate(self): + tp_config = {'traffic_profile': {'packet_sizes': {'64B': 100}}} + tp_config_obj = base.TrafficProfileConfig(tp_config) + self.assertEqual((100.0, 'fps'), tp_config_obj._parse_rate('100 ')) + self.assertEqual((200.5, 'fps'), tp_config_obj._parse_rate('200.5')) + self.assertEqual((300.8, 'fps'), tp_config_obj._parse_rate('300.8fps')) + self.assertEqual((400.2, 'fps'), + tp_config_obj._parse_rate('400.2 fps')) + self.assertEqual((500.3, '%'), tp_config_obj._parse_rate('500.3%')) + self.assertEqual((600.1, '%'), tp_config_obj._parse_rate('600.1 %')) + + def test__parse_rate_exception(self): + tp_config = {'traffic_profile': {'packet_sizes': {'64B': 100}}} + tp_config_obj = base.TrafficProfileConfig(tp_config) + with self.assertRaises(exceptions.TrafficProfileRate): + tp_config_obj._parse_rate('100Fps') + with self.assertRaises(exceptions.TrafficProfileRate): + tp_config_obj._parse_rate('100 kbps') diff --git a/yardstick/tests/unit/network_services/traffic_profile/test_fixed.py b/yardstick/tests/unit/network_services/traffic_profile/test_fixed.py index 39905e6b1..2f6713760 100644 --- a/yardstick/tests/unit/network_services/traffic_profile/test_fixed.py +++ b/yardstick/tests/unit/network_services/traffic_profile/test_fixed.py @@ -102,8 +102,7 @@ class TestFixedProfile(unittest.TestCase): 'id': 'VpeApproxVnf', 'name': 'VPEVnfSsh'}]}} def test___init__(self): - fixed_profile = \ - FixedProfile(TrafficProfile) + fixed_profile = FixedProfile(self.TRAFFIC_PROFILE) self.assertIsNotNone(fixed_profile) def test_execute(self): diff --git a/yardstick/tests/unit/network_services/traffic_profile/test_http.py b/yardstick/tests/unit/network_services/traffic_profile/test_http.py index 0d1b916a7..d44fab2b5 100644 --- a/yardstick/tests/unit/network_services/traffic_profile/test_http.py +++ b/yardstick/tests/unit/network_services/traffic_profile/test_http.py @@ -11,30 +11,29 @@ # 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. -# import unittest -from yardstick.network_services.traffic_profile.base import TrafficProfile -from yardstick.network_services.traffic_profile.http import \ - TrafficProfileGenericHTTP +from yardstick.network_services.traffic_profile import http class TestTrafficProfileGenericHTTP(unittest.TestCase): + + TP_CONFIG = {'traffic_profile': {'duration': 10}} + def test___init__(self): - traffic_profile_generic_htt_p = \ - TrafficProfileGenericHTTP(TrafficProfile) - self.assertIsNotNone(traffic_profile_generic_htt_p) + tp_generic_http = http.TrafficProfileGenericHTTP( + self.TP_CONFIG) + self.assertIsNotNone(tp_generic_http) def test_execute(self): - traffic_profile_generic_htt_p = \ - TrafficProfileGenericHTTP(TrafficProfile) + tp_generic_http = http.TrafficProfileGenericHTTP( + self.TP_CONFIG) traffic_generator = {} - self.assertIsNone( - traffic_profile_generic_htt_p.execute(traffic_generator)) + self.assertIsNone(tp_generic_http.execute(traffic_generator)) def test__send_http_request(self): - traffic_profile_generic_htt_p = \ - TrafficProfileGenericHTTP(TrafficProfile) - self.assertIsNone(traffic_profile_generic_htt_p._send_http_request( - "10.1.1.1", "250", "/req")) + tp_generic_http = http.TrafficProfileGenericHTTP( + self.TP_CONFIG) + self.assertIsNone(tp_generic_http._send_http_request( + '10.1.1.1', '250', '/req')) diff --git a/yardstick/tests/unit/network_services/traffic_profile/test_ixia_rfc2544.py b/yardstick/tests/unit/network_services/traffic_profile/test_ixia_rfc2544.py index a0abe2bbd..6f76eb77c 100644 --- a/yardstick/tests/unit/network_services/traffic_profile/test_ixia_rfc2544.py +++ b/yardstick/tests/unit/network_services/traffic_profile/test_ixia_rfc2544.py @@ -11,25 +11,14 @@ # 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. -# - -import unittest -import mock - -from copy import deepcopy -from yardstick.tests import STL_MOCKS +import copy -STLClient = mock.MagicMock() -stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) -stl_patch.start() +import mock +import unittest -if stl_patch: - from yardstick.network_services.traffic_profile.trex_traffic_profile \ - import TrexProfile - from yardstick.network_services.traffic_profile.ixia_rfc2544 import \ - IXIARFC2544Profile - from yardstick.network_services.traffic_profile import ixia_rfc2544 +from yardstick.network_services.traffic_profile import ixia_rfc2544 +from yardstick.network_services.traffic_profile import trex_traffic_profile class TestIXIARFC2544Profile(unittest.TestCase): @@ -52,7 +41,7 @@ class TestIXIARFC2544Profile(unittest.TestCase): 'traffic_profile': { 'traffic_type': 'IXIARFC2544Profile', 'frame_rate': 100}, - IXIARFC2544Profile.DOWNLINK: { + ixia_rfc2544.IXIARFC2544Profile.DOWNLINK: { 'ipv4': { 'outer_l2': { 'framesize': { @@ -73,7 +62,7 @@ class TestIXIARFC2544Profile(unittest.TestCase): 'outer_l4': { 'srcport': '2001', 'dsrport': '1234'}}}, - IXIARFC2544Profile.UPLINK: { + ixia_rfc2544.IXIARFC2544Profile.UPLINK: { 'ipv4': { 'outer_l2': { 'framesize': { @@ -97,14 +86,15 @@ class TestIXIARFC2544Profile(unittest.TestCase): 'schema': 'isb:traffic_profile:0.1'} def test_get_ixia_traffic_profile_error(self): - traffic_generator = mock.Mock(autospec=TrexProfile) + traffic_generator = mock.Mock( + autospec=trex_traffic_profile.TrexProfile) traffic_generator.my_ports = [0, 1] traffic_generator.uplink_ports = [-1] traffic_generator.downlink_ports = [1] traffic_generator.client = \ mock.Mock(return_value=True) STATIC_TRAFFIC = { - IXIARFC2544Profile.UPLINK: { + ixia_rfc2544.IXIARFC2544Profile.UPLINK: { "id": 1, "bidir": "False", "duration": 60, @@ -143,7 +133,7 @@ class TestIXIARFC2544Profile(unittest.TestCase): }, "traffic_type": "continuous" }, - IXIARFC2544Profile.DOWNLINK: { + ixia_rfc2544.IXIARFC2544Profile.DOWNLINK: { "id": 2, "bidir": "False", "duration": 60, @@ -187,7 +177,8 @@ class TestIXIARFC2544Profile(unittest.TestCase): } ixia_rfc2544.STATIC_TRAFFIC = STATIC_TRAFFIC - r_f_c2544_profile = IXIARFC2544Profile(self.TRAFFIC_PROFILE) + r_f_c2544_profile = ixia_rfc2544.IXIARFC2544Profile( + self.TRAFFIC_PROFILE) r_f_c2544_profile.rate = 100 mac = {"src_mac_0": "00:00:00:00:00:01", "src_mac_1": "00:00:00:00:00:02", @@ -199,14 +190,15 @@ class TestIXIARFC2544Profile(unittest.TestCase): self.assertIsNotNone(result) def test_get_ixia_traffic_profile(self): - traffic_generator = mock.Mock(autospec=TrexProfile) + traffic_generator = mock.Mock( + autospec=trex_traffic_profile.TrexProfile) traffic_generator.my_ports = [0, 1] traffic_generator.uplink_ports = [-1] traffic_generator.downlink_ports = [1] traffic_generator.client = \ mock.Mock(return_value=True) STATIC_TRAFFIC = { - IXIARFC2544Profile.UPLINK: { + ixia_rfc2544.IXIARFC2544Profile.UPLINK: { "id": 1, "bidir": "False", "duration": 60, @@ -246,7 +238,7 @@ class TestIXIARFC2544Profile(unittest.TestCase): }, "traffic_type": "continuous" }, - IXIARFC2544Profile.DOWNLINK: { + ixia_rfc2544.IXIARFC2544Profile.DOWNLINK: { "id": 2, "bidir": "False", "duration": 60, @@ -289,7 +281,8 @@ class TestIXIARFC2544Profile(unittest.TestCase): } ixia_rfc2544.STATIC_TRAFFIC = STATIC_TRAFFIC - r_f_c2544_profile = IXIARFC2544Profile(self.TRAFFIC_PROFILE) + r_f_c2544_profile = ixia_rfc2544.IXIARFC2544Profile( + self.TRAFFIC_PROFILE) r_f_c2544_profile.rate = 100 mac = {"src_mac_0": "00:00:00:00:00:01", "src_mac_1": "00:00:00:00:00:02", @@ -302,14 +295,15 @@ class TestIXIARFC2544Profile(unittest.TestCase): @mock.patch("yardstick.network_services.traffic_profile.ixia_rfc2544.open") def test_get_ixia_traffic_profile_v6(self, *args): - traffic_generator = mock.Mock(autospec=TrexProfile) + traffic_generator = mock.Mock( + autospec=trex_traffic_profile.TrexProfile) traffic_generator.my_ports = [0, 1] traffic_generator.uplink_ports = [-1] traffic_generator.downlink_ports = [1] traffic_generator.client = \ mock.Mock(return_value=True) STATIC_TRAFFIC = { - IXIARFC2544Profile.UPLINK: { + ixia_rfc2544.IXIARFC2544Profile.UPLINK: { "id": 1, "bidir": "False", "duration": 60, @@ -348,7 +342,7 @@ class TestIXIARFC2544Profile(unittest.TestCase): }, "traffic_type": "continuous" }, - IXIARFC2544Profile.DOWNLINK: { + ixia_rfc2544.IXIARFC2544Profile.DOWNLINK: { "id": 2, "bidir": "False", "duration": 60, @@ -392,7 +386,8 @@ class TestIXIARFC2544Profile(unittest.TestCase): } ixia_rfc2544.STATIC_TRAFFIC = STATIC_TRAFFIC - r_f_c2544_profile = IXIARFC2544Profile(self.TRAFFIC_PROFILE) + r_f_c2544_profile = ixia_rfc2544.IXIARFC2544Profile( + self.TRAFFIC_PROFILE) r_f_c2544_profile.rate = 100 mac = {"src_mac_0": "00:00:00:00:00:01", "src_mac_1": "00:00:00:00:00:02", @@ -405,7 +400,7 @@ class TestIXIARFC2544Profile(unittest.TestCase): 'traffic_profile': {'traffic_type': 'IXIARFC2544Profile', 'frame_rate': 100}, - IXIARFC2544Profile.DOWNLINK: + ixia_rfc2544.IXIARFC2544Profile.DOWNLINK: {'ipv4': {'outer_l2': {'framesize': {'64B': '100', '1518B': '0', @@ -422,7 +417,7 @@ class TestIXIARFC2544Profile(unittest.TestCase): 'dscp': 0, 'ttl': 32}, 'outer_l4': {'srcport': '2001', 'dsrport': '1234'}}}, - IXIARFC2544Profile.UPLINK: {'ipv4': + ixia_rfc2544.IXIARFC2544Profile.UPLINK: {'ipv4': {'outer_l2': {'framesize': {'64B': '100', '1518B': '0', '128B': '0', '1400B': '0', @@ -445,52 +440,114 @@ class TestIXIARFC2544Profile(unittest.TestCase): result = r_f_c2544_profile._get_ixia_traffic_profile(profile_data, mac) self.assertIsNotNone(result) + def test__init__(self): + t_profile_data = copy.deepcopy(self.TRAFFIC_PROFILE) + t_profile_data['traffic_profile']['frame_rate'] = 12345678 + r_f_c2544_profile = ixia_rfc2544.IXIARFC2544Profile(t_profile_data) + self.assertEqual(12345678, r_f_c2544_profile.rate) + + def test__get_ip_and_mask_range(self): + ip_range = '1.2.0.2-1.2.255.254' + r_f_c2544_profile = ixia_rfc2544.IXIARFC2544Profile( + self.TRAFFIC_PROFILE) + ip, mask = r_f_c2544_profile._get_ip_and_mask(ip_range) + self.assertEqual('1.2.0.2', ip) + self.assertEqual(16, mask) + + def test__get_ip_and_mask_single(self): + ip_range = '192.168.1.10' + r_f_c2544_profile = ixia_rfc2544.IXIARFC2544Profile( + self.TRAFFIC_PROFILE) + ip, mask = r_f_c2544_profile._get_ip_and_mask(ip_range) + self.assertEqual('192.168.1.10', ip) + self.assertIsNone(mask) + + def test__get_fixed_and_mask_range(self): + fixed_mask = '8-48' + r_f_c2544_profile = ixia_rfc2544.IXIARFC2544Profile( + self.TRAFFIC_PROFILE) + fixed, mask = r_f_c2544_profile._get_fixed_and_mask(fixed_mask) + self.assertEqual(8, fixed) + self.assertEqual(48, mask) + + def test__get_fixed_and_mask_single(self): + fixed_mask = 1234 + r_f_c2544_profile = ixia_rfc2544.IXIARFC2544Profile( + self.TRAFFIC_PROFILE) + fixed, mask = r_f_c2544_profile._get_fixed_and_mask(fixed_mask) + self.assertEqual(1234, fixed) + self.assertEqual(0, mask) + def test__get_ixia_traffic_profile_default_args(self): - r_f_c2544_profile = IXIARFC2544Profile(self.TRAFFIC_PROFILE) + r_f_c2544_profile = ixia_rfc2544.IXIARFC2544Profile( + self.TRAFFIC_PROFILE) expected = {} result = r_f_c2544_profile._get_ixia_traffic_profile({}) self.assertDictEqual(result, expected) def test__ixia_traffic_generate(self): - traffic_generator = mock.Mock(autospec=TrexProfile) + traffic_generator = mock.Mock( + autospec=trex_traffic_profile.TrexProfile) traffic_generator.networks = { "uplink_0": ["xe0"], "downlink_0": ["xe1"], } traffic_generator.client = \ mock.Mock(return_value=True) - traffic = {IXIARFC2544Profile.DOWNLINK: {'iload': 10}, - IXIARFC2544Profile.UPLINK: {'iload': 10}} + traffic = {ixia_rfc2544.IXIARFC2544Profile.DOWNLINK: {'iload': 10}, + ixia_rfc2544.IXIARFC2544Profile.UPLINK: {'iload': 10}} ixia_obj = mock.MagicMock() - r_f_c2544_profile = IXIARFC2544Profile(self.TRAFFIC_PROFILE) + r_f_c2544_profile = ixia_rfc2544.IXIARFC2544Profile( + self.TRAFFIC_PROFILE) r_f_c2544_profile.rate = 100 result = r_f_c2544_profile._ixia_traffic_generate(traffic, ixia_obj) self.assertIsNone(result) - def test_execute(self): - traffic_generator = mock.Mock(autospec=TrexProfile) - traffic_generator.networks = { - "uplink_0": ["xe0"], - "downlink_0": ["xe1"], - } - traffic_generator.client = \ - mock.Mock(return_value=True) - r_f_c2544_profile = IXIARFC2544Profile(self.TRAFFIC_PROFILE) - r_f_c2544_profile.first_run = True - r_f_c2544_profile.params = {IXIARFC2544Profile.DOWNLINK: {'iload': 10}, - IXIARFC2544Profile.UPLINK: {'iload': 10}} + def test_execute_traffic_first_run(self): + rfc2544_profile = ixia_rfc2544.IXIARFC2544Profile(self.TRAFFIC_PROFILE) + rfc2544_profile.first_run = True + rfc2544_profile.rate = 50 + with mock.patch.object(rfc2544_profile, '_get_ixia_traffic_profile') \ + as mock_get_tp, \ + mock.patch.object(rfc2544_profile, '_ixia_traffic_generate') \ + as mock_tgenerate, \ + mock.patch.object(rfc2544_profile, 'update_traffic_profile') \ + as mock_update_tp: + mock_get_tp.return_value = 'fake_tprofile' + output = rfc2544_profile.execute_traffic(mock.ANY, + ixia_obj=mock.ANY) - r_f_c2544_profile.get_streams = mock.Mock() - r_f_c2544_profile.full_profile = {} - r_f_c2544_profile._get_ixia_traffic_profile = mock.Mock() - r_f_c2544_profile.get_multiplier = mock.Mock() - r_f_c2544_profile._ixia_traffic_generate = mock.Mock() - ixia_obj = mock.MagicMock() - self.assertIsNone(r_f_c2544_profile.execute_traffic(traffic_generator, ixia_obj)) + self.assertTrue(output) + self.assertFalse(rfc2544_profile.first_run) + self.assertEqual(50, rfc2544_profile.max_rate) + self.assertEqual(0, rfc2544_profile.min_rate) + mock_get_tp.assert_called_once() + mock_tgenerate.assert_called_once() + mock_update_tp.assert_called_once() + + def test_execute_traffic_not_first_run(self): + rfc2544_profile = ixia_rfc2544.IXIARFC2544Profile(self.TRAFFIC_PROFILE) + rfc2544_profile.first_run = False + rfc2544_profile.max_rate = 70 + rfc2544_profile.min_rate = 0 + with mock.patch.object(rfc2544_profile, '_get_ixia_traffic_profile') \ + as mock_get_tp, \ + mock.patch.object(rfc2544_profile, '_ixia_traffic_generate') \ + as mock_tgenerate: + mock_get_tp.return_value = 'fake_tprofile' + rfc2544_profile.full_profile = mock.ANY + output = rfc2544_profile.execute_traffic(mock.ANY, + ixia_obj=mock.ANY) + + self.assertFalse(output) + self.assertEqual(35.0, rfc2544_profile.rate) + mock_get_tp.assert_called_once() + mock_tgenerate.assert_called_once() def test_update_traffic_profile(self): - traffic_generator = mock.Mock(autospec=TrexProfile) + traffic_generator = mock.Mock( + autospec=trex_traffic_profile.TrexProfile) traffic_generator.networks = { "uplink_0": ["xe0"], # private, one value for intfs "downlink_0": ["xe1", "xe2"], # public, two values for intfs @@ -502,13 +559,13 @@ class TestIXIARFC2544Profile(unittest.TestCase): traffic_generator.vnfd_helper.port_num.side_effect = ports_expected traffic_generator.client.return_value = True - traffic_profile = deepcopy(self.TRAFFIC_PROFILE) + traffic_profile = copy.deepcopy(self.TRAFFIC_PROFILE) traffic_profile.update({ "uplink_0": ["xe0"], "downlink_0": ["xe1", "xe2"], }) - r_f_c2544_profile = IXIARFC2544Profile(traffic_profile) + r_f_c2544_profile = ixia_rfc2544.IXIARFC2544Profile(traffic_profile) r_f_c2544_profile.full_profile = {} r_f_c2544_profile.get_streams = mock.Mock() @@ -516,112 +573,89 @@ class TestIXIARFC2544Profile(unittest.TestCase): r_f_c2544_profile.update_traffic_profile(traffic_generator)) self.assertEqual(r_f_c2544_profile.ports, ports_expected) - def test_get_drop_percentage(self): - r_f_c2544_profile = IXIARFC2544Profile(self.TRAFFIC_PROFILE) - r_f_c2544_profile.params = self.PROFILE - ixia_obj = mock.MagicMock() - r_f_c2544_profile.execute = mock.Mock() - r_f_c2544_profile._get_ixia_traffic_profile = mock.Mock() - r_f_c2544_profile._ixia_traffic_generate = mock.Mock() - r_f_c2544_profile.get_multiplier = mock.Mock() - r_f_c2544_profile.tmp_throughput = 0 - r_f_c2544_profile.tmp_drop = 0 - r_f_c2544_profile.full_profile = {} - samples = {} - for ifname in range(1): - name = "xe{}".format(ifname) - samples[name] = {"rx_throughput_fps": 20, - "tx_throughput_fps": 20, - "rx_throughput_mbps": 10, - "tx_throughput_mbps": 10, - "RxThroughput": 10, - "TxThroughput": 10, - "in_packets": 1000, - "out_packets": 1000} - tol_min = 100.0 - tolerance = 0.0 - self.assertIsNotNone( - r_f_c2544_profile.get_drop_percentage(samples, tol_min, tolerance, - ixia_obj)) - - def test_get_drop_percentage_update(self): - r_f_c2544_profile = IXIARFC2544Profile(self.TRAFFIC_PROFILE) - r_f_c2544_profile.params = self.PROFILE - ixia_obj = mock.MagicMock() - r_f_c2544_profile.execute = mock.Mock() - r_f_c2544_profile._get_ixia_traffic_profile = mock.Mock() - r_f_c2544_profile._ixia_traffic_generate = mock.Mock() - r_f_c2544_profile.get_multiplier = mock.Mock() - r_f_c2544_profile.tmp_throughput = 0 - r_f_c2544_profile.tmp_drop = 0 - r_f_c2544_profile.full_profile = {} - samples = {} - for ifname in range(1): - name = "xe{}".format(ifname) - samples[name] = {"rx_throughput_fps": 20, - "tx_throughput_fps": 20, - "rx_throughput_mbps": 10, - "tx_throughput_mbps": 10, - "RxThroughput": 10, - "TxThroughput": 10, - "in_packets": 1000, - "out_packets": 1002} - tol_min = 0.0 - tolerance = 1.0 - self.assertIsNotNone( - r_f_c2544_profile.get_drop_percentage(samples, tol_min, tolerance, - ixia_obj)) - - def test_get_drop_percentage_div_zero(self): - r_f_c2544_profile = IXIARFC2544Profile(self.TRAFFIC_PROFILE) - r_f_c2544_profile.params = self.PROFILE - ixia_obj = mock.MagicMock() - r_f_c2544_profile.execute = mock.Mock() - r_f_c2544_profile._get_ixia_traffic_profile = mock.Mock() - r_f_c2544_profile._ixia_traffic_generate = mock.Mock() - r_f_c2544_profile.get_multiplier = mock.Mock() - r_f_c2544_profile.tmp_throughput = 0 - r_f_c2544_profile.tmp_drop = 0 - r_f_c2544_profile.full_profile = {} - samples = {} - for ifname in range(1): - name = "xe{}".format(ifname) - samples[name] = {"rx_throughput_fps": 20, - "tx_throughput_fps": 20, - "rx_throughput_mbps": 10, - "tx_throughput_mbps": 10, - "RxThroughput": 10, - "TxThroughput": 10, - "in_packets": 1000, - "out_packets": 0} - tol_min = 0.0 - tolerance = 0.0 - r_f_c2544_profile.tmp_throughput = 0 - self.assertIsNotNone( - r_f_c2544_profile.get_drop_percentage(samples, tol_min, tolerance, - ixia_obj)) - - def test_get_multiplier(self): - r_f_c2544_profile = IXIARFC2544Profile(self.TRAFFIC_PROFILE) - r_f_c2544_profile.max_rate = 100 - r_f_c2544_profile.min_rate = 100 - self.assertEqual("1.0", r_f_c2544_profile.get_multiplier()) - - def test_start_ixia_latency(self): - traffic_generator = mock.Mock(autospec=TrexProfile) - traffic_generator.networks = { - "uplink_0": ["xe0"], - "downlink_0": ["xe1"], - } - traffic_generator.client = \ - mock.Mock(return_value=True) - r_f_c2544_profile = IXIARFC2544Profile(self.TRAFFIC_PROFILE) - r_f_c2544_profile.max_rate = 100 - r_f_c2544_profile.min_rate = 100 - ixia_obj = mock.MagicMock() - r_f_c2544_profile._get_ixia_traffic_profile = \ - mock.Mock(return_value={}) - r_f_c2544_profile.full_profile = {} - r_f_c2544_profile._ixia_traffic_generate = mock.Mock() - self.assertIsNone( - r_f_c2544_profile.start_ixia_latency(traffic_generator, ixia_obj)) + def test_get_drop_percentage_completed(self): + samples = {'iface_name_1': + {'RxThroughput': 10, 'TxThroughput': 10, + 'in_packets': 1000, 'out_packets': 1000}, + 'iface_name_2': + {'RxThroughput': 11, 'TxThroughput': 13, + 'in_packets': 1005, 'out_packets': 1007} + } + rfc2544_profile = ixia_rfc2544.IXIARFC2544Profile(self.TRAFFIC_PROFILE) + completed, samples = rfc2544_profile.get_drop_percentage(samples, 0, 1) + self.assertTrue(completed) + self.assertEqual(23.0, samples['TxThroughput']) + self.assertEqual(21.0, samples['RxThroughput']) + self.assertEqual(0.099651, samples['DropPercentage']) + + def test_get_drop_percentage_over_drop_percentage(self): + samples = {'iface_name_1': + {'RxThroughput': 10, 'TxThroughput': 10, + 'in_packets': 1000, 'out_packets': 1000}, + 'iface_name_2': + {'RxThroughput': 11, 'TxThroughput': 13, + 'in_packets': 1005, 'out_packets': 1007} + } + rfc2544_profile = ixia_rfc2544.IXIARFC2544Profile(self.TRAFFIC_PROFILE) + rfc2544_profile.rate = 1000 + completed, samples = rfc2544_profile.get_drop_percentage( + samples, 0, 0.05) + self.assertFalse(completed) + self.assertEqual(23.0, samples['TxThroughput']) + self.assertEqual(21.0, samples['RxThroughput']) + self.assertEqual(0.099651, samples['DropPercentage']) + self.assertEqual(rfc2544_profile.rate, rfc2544_profile.max_rate) + + def test_get_drop_percentage_under_drop_percentage(self): + samples = {'iface_name_1': + {'RxThroughput': 10, 'TxThroughput': 10, + 'in_packets': 1000, 'out_packets': 1000}, + 'iface_name_2': + {'RxThroughput': 11, 'TxThroughput': 13, + 'in_packets': 1005, 'out_packets': 1007} + } + rfc2544_profile = ixia_rfc2544.IXIARFC2544Profile(self.TRAFFIC_PROFILE) + rfc2544_profile.rate = 1000 + completed, samples = rfc2544_profile.get_drop_percentage( + samples, 0.2, 1) + self.assertFalse(completed) + self.assertEqual(23.0, samples['TxThroughput']) + self.assertEqual(21.0, samples['RxThroughput']) + self.assertEqual(0.099651, samples['DropPercentage']) + self.assertEqual(rfc2544_profile.rate, rfc2544_profile.min_rate) + + @mock.patch.object(ixia_rfc2544.LOG, 'info') + def test_get_drop_percentage_not_flow(self, *args): + samples = {'iface_name_1': + {'RxThroughput': 0, 'TxThroughput': 10, + 'in_packets': 1000, 'out_packets': 0}, + 'iface_name_2': + {'RxThroughput': 0, 'TxThroughput': 13, + 'in_packets': 1005, 'out_packets': 0} + } + rfc2544_profile = ixia_rfc2544.IXIARFC2544Profile(self.TRAFFIC_PROFILE) + rfc2544_profile.rate = 1000 + completed, samples = rfc2544_profile.get_drop_percentage( + samples, 0.2, 1) + self.assertFalse(completed) + self.assertEqual(23.0, samples['TxThroughput']) + self.assertEqual(0, samples['RxThroughput']) + self.assertEqual(100, samples['DropPercentage']) + self.assertEqual(rfc2544_profile.rate, rfc2544_profile.max_rate) + + def test_get_drop_percentage_first_run(self): + samples = {'iface_name_1': + {'RxThroughput': 10, 'TxThroughput': 10, + 'in_packets': 1000, 'out_packets': 1000}, + 'iface_name_2': + {'RxThroughput': 11, 'TxThroughput': 13, + 'in_packets': 1005, 'out_packets': 1007} + } + rfc2544_profile = ixia_rfc2544.IXIARFC2544Profile(self.TRAFFIC_PROFILE) + completed, samples = rfc2544_profile.get_drop_percentage( + samples, 0, 1, first_run=True) + self.assertTrue(completed) + self.assertEqual(23.0, samples['TxThroughput']) + self.assertEqual(21.0, samples['RxThroughput']) + self.assertEqual(0.099651, samples['DropPercentage']) + self.assertEqual(33.45, rfc2544_profile.rate) diff --git a/yardstick/tests/unit/network_services/traffic_profile/test_pktgen.py b/yardstick/tests/unit/network_services/traffic_profile/test_pktgen.py new file mode 100644 index 000000000..08542b4f1 --- /dev/null +++ b/yardstick/tests/unit/network_services/traffic_profile/test_pktgen.py @@ -0,0 +1,63 @@ +# Copyright (c) 2018 Intel Corporation +# +# 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. + +import mock + +from yardstick.common import utils +from yardstick.network_services.traffic_profile import pktgen +from yardstick.tests.unit import base as ut_base + + +class TestIXIARFC2544Profile(ut_base.BaseUnitTestCase): + + def setUp(self): + self._tp_config = {'traffic_profile': {}} + self._host = 'localhost' + self._port = '12345' + self.tp = pktgen.PktgenTrafficProfile(self._tp_config) + self.tp.init(self._host, self._port) + self._mock_send_socket_command = mock.patch.object( + utils, 'send_socket_command', return_value=0) + self.mock_send_socket_command = self._mock_send_socket_command.start() + self.addCleanup(self._stop_mock) + + def _stop_mock(self): + self._mock_send_socket_command.stop() + + def test_start(self): + self.tp.start() + self.mock_send_socket_command.assert_called_once_with( + self._host, self._port, 'pktgen.start("0")') + + def test_stop(self): + self.tp.stop() + self.mock_send_socket_command.assert_called_once_with( + self._host, self._port, 'pktgen.stop("0")') + + def test_rate(self): + rate = 75 + self.tp.rate(rate) + command = 'pktgen.set("0", "rate", 75)' + self.mock_send_socket_command.assert_called_once_with( + self._host, self._port, command) + + def test_clear_all_stats(self): + self.tp.clear_all_stats() + self.mock_send_socket_command.assert_called_once_with( + self._host, self._port, 'clr') + + def test_help(self): + self.tp.help() + self.mock_send_socket_command.assert_called_once_with( + self._host, self._port, 'help') diff --git a/yardstick/tests/unit/network_services/traffic_profile/test_prox_binsearch.py b/yardstick/tests/unit/network_services/traffic_profile/test_prox_binsearch.py index 58343ffb2..c062308e8 100644 --- a/yardstick/tests/unit/network_services/traffic_profile/test_prox_binsearch.py +++ b/yardstick/tests/unit/network_services/traffic_profile/test_prox_binsearch.py @@ -11,23 +11,23 @@ # 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. -# import unittest import mock -from yardstick.tests import STL_MOCKS +from yardstick.network_services.vnf_generic.vnf.prox_helpers import ProxTestDataTuple +from yardstick.network_services.traffic_profile import prox_binsearch -STLClient = mock.MagicMock() -stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) -stl_patch.start() -if stl_patch: - from yardstick.network_services.vnf_generic.vnf.prox_helpers import ProxTestDataTuple - from yardstick.network_services.traffic_profile.prox_binsearch import ProxBinSearchProfile +class TestProxBinSearchProfile(unittest.TestCase): + def setUp(self): + self._mock_log_info = mock.patch.object(prox_binsearch.LOG, 'info') + self.mock_log_info = self._mock_log_info.start() + self.addCleanup(self._stop_mocks) -class TestProxBinSearchProfile(unittest.TestCase): + def _stop_mocks(self): + self._mock_log_info.stop() def test_execute_1(self): def target(*args, **_): @@ -51,23 +51,30 @@ class TestProxBinSearchProfile(unittest.TestCase): fail_tuple = ProxTestDataTuple(10.0, 1, 2, 3, 4, [5.6, 5.7, 5.8], 850, 1000, 123.4) traffic_generator = mock.MagicMock() + attrs1 = {'get.return_value' : 10} + traffic_generator.scenario_helper.all_options.configure_mock(**attrs1) + + attrs2 = {'__getitem__.return_value' : 10, 'get.return_value': 10} + traffic_generator.scenario_helper.scenario_cfg["runner"].configure_mock(**attrs2) profile_helper = mock.MagicMock() profile_helper.run_test = target - profile = ProxBinSearchProfile(tp_config) + profile = prox_binsearch.ProxBinSearchProfile(tp_config) profile.init(mock.MagicMock()) profile._profile_helper = profile_helper profile.execute_traffic(traffic_generator) + self.assertEqual(round(profile.current_lower, 2), 74.69) self.assertEqual(round(profile.current_upper, 2), 76.09) - self.assertEqual(len(runs), 7) + self.assertEqual(len(runs), 77) # Result Samples inc theor_max - result_tuple = {"Result_Actual_throughput": 7.5e-07, - "Result_theor_max_throughput": 1.234e-10, - "Result_pktSize": 200} + result_tuple = {'Result_Actual_throughput': 5e-07, + 'Result_theor_max_throughput': 7.5e-07, + 'Result_pktSize': 200} + profile.queue.put.assert_called_with(result_tuple) success_result_tuple = {"Success_CurrentDropPackets": 0.5, @@ -122,11 +129,16 @@ class TestProxBinSearchProfile(unittest.TestCase): fail_tuple = ProxTestDataTuple(10.0, 1, 2, 3, 4, [5.6, 5.7, 5.8], 850, 1000, 123.4) traffic_generator = mock.MagicMock() + attrs1 = {'get.return_value': 10} + traffic_generator.scenario_helper.all_options.configure_mock(**attrs1) + + attrs2 = {'__getitem__.return_value': 0, 'get.return_value': 0} + traffic_generator.scenario_helper.scenario_cfg["runner"].configure_mock(**attrs2) profile_helper = mock.MagicMock() profile_helper.run_test = target - profile = ProxBinSearchProfile(tp_config) + profile = prox_binsearch.ProxBinSearchProfile(tp_config) profile.init(mock.MagicMock()) profile._profile_helper = profile_helper @@ -161,7 +173,7 @@ class TestProxBinSearchProfile(unittest.TestCase): profile_helper = mock.MagicMock() profile_helper.run_test = target - profile = ProxBinSearchProfile(tp_config) + profile = prox_binsearch.ProxBinSearchProfile(tp_config) profile.init(mock.MagicMock()) profile._profile_helper = profile_helper @@ -171,7 +183,8 @@ class TestProxBinSearchProfile(unittest.TestCase): # Result Samples - result_tuple = {"Result_theor_max_throughput": 0, "Result_pktSize": 200} + result_tuple = {'Result_Actual_throughput': 0, "Result_theor_max_throughput": 0, + "Result_pktSize": 200} profile.queue.put.assert_called_with(result_tuple) # Check for success_ tuple (None expected) @@ -181,3 +194,81 @@ class TestProxBinSearchProfile(unittest.TestCase): for k in call_detail: if "Success_" in k: self.assertRaises(AttributeError) + + def test_execute_4(self): + + def target(*args, **_): + runs.append(args[2]) + if args[2] < 0 or args[2] > 100: + raise RuntimeError(' '.join([str(args), str(runs)])) + if args[2] > 75.0: + return fail_tuple, {} + return success_tuple, {} + + tp_config = { + 'traffic_profile': { + 'packet_sizes': [200], + 'test_precision': 2.0, + 'tolerated_loss': 0.001, + }, + } + + runs = [] + success_tuple = ProxTestDataTuple(10.0, 1, 2, 3, 4, [5.1, 5.2, 5.3], 995, 1000, 123.4) + fail_tuple = ProxTestDataTuple(10.0, 1, 2, 3, 4, [5.6, 5.7, 5.8], 850, 1000, 123.4) + + traffic_generator = mock.MagicMock() + attrs1 = {'get.return_value': 100000} + traffic_generator.scenario_helper.all_options.configure_mock(**attrs1) + + attrs2 = {'__getitem__.return_value': 0, 'get.return_value': 0} + traffic_generator.scenario_helper.scenario_cfg["runner"].configure_mock(**attrs2) + + profile_helper = mock.MagicMock() + profile_helper.run_test = target + + profile = prox_binsearch.ProxBinSearchProfile(tp_config) + profile.init(mock.MagicMock()) + profile._profile_helper = profile_helper + + profile.execute_traffic(traffic_generator) + self.assertEqual(round(profile.current_lower, 2), 74.69) + self.assertEqual(round(profile.current_upper, 2), 76.09) + self.assertEqual(len(runs), 7) + + # Result Samples inc theor_max + result_tuple = {'Result_Actual_throughput': 5e-07, + 'Result_theor_max_throughput': 7.5e-07, + 'Result_pktSize': 200} + + profile.queue.put.assert_called_with(result_tuple) + + success_result_tuple = {"Success_CurrentDropPackets": 0.5, + "Success_DropPackets": 0.5, + "Success_LatencyAvg": 5.3, + "Success_LatencyMax": 5.2, + "Success_LatencyMin": 5.1, + "Success_PktSize": 200, + "Success_RxThroughput": 7.5e-07, + "Success_Throughput": 7.5e-07, + "Success_TxThroughput": 0.00012340000000000002} + + calls = profile.queue.put(success_result_tuple) + profile.queue.put.assert_has_calls(calls) + + success_result_tuple2 = {"Success_CurrentDropPackets": 0.5, + "Success_DropPackets": 0.5, + "Success_LatencyAvg": 5.3, + "Success_LatencyMax": 5.2, + "Success_LatencyMin": 5.1, + "Success_PktSize": 200, + "Success_RxThroughput": 7.5e-07, + "Success_Throughput": 7.5e-07, + "Success_TxThroughput": 123.4, + "Success_can_be_lost": 409600, + "Success_drop_total": 20480, + "Success_rx_total": 4075520, + "Success_tx_total": 4096000} + + calls = profile.queue.put(success_result_tuple2) + profile.queue.put.assert_has_calls(calls) diff --git a/yardstick/tests/unit/network_services/traffic_profile/test_prox_profile.py b/yardstick/tests/unit/network_services/traffic_profile/test_prox_profile.py index e466305ea..cf31cc27c 100644 --- a/yardstick/tests/unit/network_services/traffic_profile/test_prox_profile.py +++ b/yardstick/tests/unit/network_services/traffic_profile/test_prox_profile.py @@ -124,5 +124,5 @@ class TestProxProfile(unittest.TestCase): for _ in profile.bounds_iterator(mock_logger): pass - self.assertEqual(mock_logger.debug.call_count, 1) + mock_logger.debug.assert_called_once() self.assertEqual(mock_logger.info.call_count, 10) diff --git a/yardstick/tests/unit/network_services/traffic_profile/test_rfc2544.py b/yardstick/tests/unit/network_services/traffic_profile/test_rfc2544.py index 2684e0ba1..a4fdc8d04 100644 --- a/yardstick/tests/unit/network_services/traffic_profile/test_rfc2544.py +++ b/yardstick/tests/unit/network_services/traffic_profile/test_rfc2544.py @@ -11,33 +11,26 @@ # 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. -# -import unittest import mock -from yardstick.tests import STL_MOCKS - +from trex_stl_lib import api as Pkt +from trex_stl_lib import trex_stl_client +from trex_stl_lib import trex_stl_packet_builder_scapy +from trex_stl_lib import trex_stl_streams -STLClient = mock.MagicMock() -stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) -stl_patch.start() +from yardstick.network_services.traffic_profile import rfc2544 +from yardstick.tests.unit import base -if stl_patch: - from yardstick.network_services.traffic_profile.trex_traffic_profile \ - import TrexProfile - from yardstick.network_services.traffic_profile.rfc2544 import \ - RFC2544Profile - -class TestRFC2544Profile(unittest.TestCase): +class TestRFC2544Profile(base.BaseUnitTestCase): TRAFFIC_PROFILE = { "schema": "isb:traffic_profile:0.1", "name": "fixed", "description": "Fixed traffic profile to run UDP traffic", "traffic_profile": { "traffic_type": "FixedTraffic", - "frame_rate": 100, # pps + "frame_rate": 100, "flow_number": 10, "frame_size": 64}} @@ -45,233 +38,252 @@ class TestRFC2544Profile(unittest.TestCase): 'name': 'rfc2544', 'traffic_profile': {'traffic_type': 'RFC2544Profile', 'frame_rate': 100}, - 'downlink_0': {'ipv4': - {'outer_l2': {'framesize': - {'64B': '100', '1518B': '0', - '128B': '0', '1400B': '0', - '256B': '0', '373b': '0', - '570B': '0'}}, - 'outer_l3v4': {'dstip4': '1.1.1.1-1.15.255.255', - 'proto': 'udp', - 'srcip4': '90.90.1.1-90.105.255.255', - 'dscp': 0, 'ttl': 32, 'count': 1}, - 'outer_l4': {'srcport': '2001', - 'dsrport': '1234', 'count': 1}}}, - 'uplink_0': {'ipv4': - {'outer_l2': {'framesize': - {'64B': '100', '1518B': '0', - '128B': '0', '1400B': '0', - '256B': '0', '373b': '0', - '570B': '0'}}, - 'outer_l3v4': {'dstip4': '9.9.1.1-90.105.255.255', - 'proto': 'udp', - 'srcip4': '1.1.1.1-1.15.255.255', - 'dscp': 0, 'ttl': 32, 'count': 1}, - 'outer_l4': {'dstport': '2001', - 'srcport': '1234', 'count': 1}}}, + 'downlink_0': + {'ipv4': + {'outer_l2': + {'framesize': + {'64B': '100', '1518B': '0', + '128B': '0', '1400B': '0', + '256B': '0', '373b': '0', + '570B': '0'}}, + 'outer_l3v4': + {'dstip4': '1.1.1.1-1.15.255.255', + 'proto': 'udp', + 'srcip4': '90.90.1.1-90.105.255.255', + 'dscp': 0, 'ttl': 32, 'count': 1}, + 'outer_l4': + {'srcport': '2001', + 'dsrport': '1234', 'count': 1}}}, + 'uplink_0': + {'ipv4': + {'outer_l2': + {'framesize': + {'64B': '100', '1518B': '0', + '128B': '0', '1400B': '0', + '256B': '0', '373b': '0', + '570B': '0'}}, + 'outer_l3v4': + {'dstip4': '9.9.1.1-90.105.255.255', + 'proto': 'udp', + 'srcip4': '1.1.1.1-1.15.255.255', + 'dscp': 0, 'ttl': 32, 'count': 1}, + 'outer_l4': + {'dstport': '2001', + 'srcport': '1234', 'count': 1}}}, 'schema': 'isb:traffic_profile:0.1'} def test___init__(self): - r_f_c2544_profile = RFC2544Profile(self.TRAFFIC_PROFILE) - self.assertIsNotNone(r_f_c2544_profile.rate) + rfc2544_profile = rfc2544.RFC2544Profile(self.TRAFFIC_PROFILE) + self.assertEqual(rfc2544_profile.max_rate, rfc2544_profile.rate) + self.assertEqual(0, rfc2544_profile.min_rate) - def test_execute(self): - traffic_generator = mock.Mock(autospec=TrexProfile) - traffic_generator.networks = { - "uplink_0": ["xe0"], - "downlink_0": ["xe1"], - } - traffic_generator.client.return_value = True - r_f_c2544_profile = RFC2544Profile(self.TRAFFIC_PROFILE) - r_f_c2544_profile.params = self.PROFILE - r_f_c2544_profile.first_run = True - self.assertIsNone(r_f_c2544_profile.execute_traffic(traffic_generator)) + def test_stop_traffic(self): + rfc2544_profile = rfc2544.RFC2544Profile(self.TRAFFIC_PROFILE) + mock_generator = mock.Mock() + rfc2544_profile.stop_traffic(traffic_generator=mock_generator) + mock_generator.client.stop.assert_called_once() + mock_generator.client.reset.assert_called_once() + mock_generator.client.remove_all_streams.assert_called_once() - def test_get_drop_percentage(self): - traffic_generator = mock.Mock(autospec=TrexProfile) - traffic_generator.networks = { - "uplink_0": ["xe0"], - "downlink_0": ["xe1"], - } - traffic_generator.client.return_value = True + def test_execute_traffic(self): + rfc2544_profile = rfc2544.RFC2544Profile(self.TRAFFIC_PROFILE) + mock_generator = mock.Mock() + mock_generator.networks = { + 'downlink_0': ['xe0', 'xe1'], + 'uplink_0': ['xe2', 'xe3'], + 'downlink_1': []} + mock_generator.port_num.side_effect = [10, 20, 30, 40] + mock_generator.rfc2544_helper.correlated_traffic = False + rfc2544_profile.params = { + 'downlink_0': 'profile1', + 'uplink_0': 'profile2'} - r_f_c2544_profile = RFC2544Profile(self.TRAFFIC_PROFILE) - r_f_c2544_profile.params = self.PROFILE - r_f_c2544_profile.register_generator(traffic_generator) - self.assertIsNone(r_f_c2544_profile.execute_traffic(traffic_generator)) + with mock.patch.object(rfc2544_profile, '_create_profile') as \ + mock_create_profile: + rfc2544_profile.execute_traffic(traffic_generator=mock_generator) + mock_create_profile.assert_has_calls([ + mock.call('profile1', rfc2544_profile.rate, mock.ANY), + mock.call('profile1', rfc2544_profile.rate, mock.ANY), + mock.call('profile2', rfc2544_profile.rate, mock.ANY), + mock.call('profile2', rfc2544_profile.rate, mock.ANY)]) + mock_generator.client.add_streams.assert_has_calls([ + mock.call(mock.ANY, ports=[10]), + mock.call(mock.ANY, ports=[20]), + mock.call(mock.ANY, ports=[30]), + mock.call(mock.ANY, ports=[40])]) + mock_generator.client.start(ports=[10, 20, 30, 40], + duration=rfc2544_profile.config.duration, + force=True) - samples = {} - for ifname in range(1): - name = "xe{}".format(ifname) - samples[name] = { - "rx_throughput_fps": 20, - "tx_throughput_fps": 20, - "rx_throughput_mbps": 10, - "tx_throughput_mbps": 10, - "in_packets": 1000, - "out_packets": 1000, - } + @mock.patch.object(trex_stl_streams, 'STLProfile') + def test__create_profile(self, mock_stl_profile): + rfc2544_profile = rfc2544.RFC2544Profile(self.TRAFFIC_PROFILE) + port_pg_id = mock.ANY + profile_data = {'packetid_1': {'outer_l2': {'framesize': 'imix_info'}}} + rate = 100 + with mock.patch.object(rfc2544_profile, '_create_imix_data') as \ + mock_create_imix, \ + mock.patch.object(rfc2544_profile, '_create_vm') as \ + mock_create_vm, \ + mock.patch.object(rfc2544_profile, '_create_streams') as \ + mock_create_streams: + mock_create_imix.return_value = 'imix_data' + mock_create_streams.return_value = ['stream1'] + rfc2544_profile._create_profile(profile_data, rate, port_pg_id) - expected = { - 'DropPercentage': 0.0, - 'RxThroughput': 100 / 3.0, - 'TxThroughput': 100 / 3.0, - 'CurrentDropPercentage': 0.0, - 'Throughput': 66.66666666666667, - 'xe0': { - 'tx_throughput_fps': 20, - 'in_packets': 1000, - 'out_packets': 1000, - 'rx_throughput_mbps': 10, - 'tx_throughput_mbps': 10, - 'rx_throughput_fps': 20, - }, - } - traffic_generator.generate_samples.return_value = samples - traffic_generator.RUN_DURATION = 30 - traffic_generator.rfc2544_helper.tolerance_low = 0.0001 - traffic_generator.rfc2544_helper.tolerance_high = 0.0001 - result = r_f_c2544_profile.get_drop_percentage(traffic_generator) - self.assertDictEqual(result, expected) + mock_create_imix.assert_called_once_with('imix_info') + mock_create_vm.assert_called_once_with( + {'outer_l2': {'framesize': 'imix_info'}}) + mock_create_streams.assert_called_once_with('imix_data', 100, + port_pg_id) + mock_stl_profile.assert_called_once_with(['stream1']) - def test_get_drop_percentage_update(self): - traffic_generator = mock.Mock(autospec=RFC2544Profile) - traffic_generator.networks = { - "uplink_0": ["xe0"], - "downlink_0": ["xe1"], - } - traffic_generator.client = mock.Mock(return_value=True) + def test__create_imix_data(self): + rfc2544_profile = rfc2544.RFC2544Profile(self.TRAFFIC_PROFILE) + data = {'64B': 50, '128B': 50} + self.assertEqual({'64': 50.0, '128': 50.0}, + rfc2544_profile._create_imix_data(data)) + data = {'64B': 1, '128b': 3} + self.assertEqual({'64': 25.0, '128': 75.0}, + rfc2544_profile._create_imix_data(data)) + data = {} + self.assertEqual({}, rfc2544_profile._create_imix_data(data)) - r_f_c2544_profile = RFC2544Profile(self.TRAFFIC_PROFILE) - r_f_c2544_profile.params = self.PROFILE - r_f_c2544_profile.register_generator(traffic_generator) - self.assertIsNone(r_f_c2544_profile.execute_traffic()) + def test__create_vm(self): + packet = {'outer_l2': 'l2_definition'} + rfc2544_profile = rfc2544.RFC2544Profile(self.TRAFFIC_PROFILE) + with mock.patch.object(rfc2544_profile, '_set_outer_l2_fields') as \ + mock_l2_fileds: + rfc2544_profile._create_vm(packet) + mock_l2_fileds.assert_called_once_with('l2_definition') - samples = {} - for ifname in range(1): - name = "xe{}".format(ifname) - samples[name] = { - "rx_throughput_fps": 20, - "tx_throughput_fps": 20, - "rx_throughput_mbps": 10, - "tx_throughput_mbps": 10, - "in_packets": 1000, - "out_packets": 1002, - } - expected = { - 'DropPercentage': 0.1996, - 'RxThroughput': 33.333333333333336, - 'TxThroughput': 33.4, - 'CurrentDropPercentage': 0.1996, - 'Throughput': 66.66666666666667, - 'xe0': { - 'tx_throughput_fps': 20, - 'in_packets': 1000, - 'out_packets': 1002, - 'rx_throughput_mbps': 10, - 'tx_throughput_mbps': 10, - 'rx_throughput_fps': 20, - }, - } - traffic_generator.generate_samples = mock.MagicMock( - return_value=samples) - traffic_generator.RUN_DURATION = 30 - traffic_generator.rfc2544_helper.tolerance_low = 0.0001 - traffic_generator.rfc2544_helper.tolerance_high = 0.0001 - result = r_f_c2544_profile.get_drop_percentage(traffic_generator) - self.assertDictEqual(expected, result) + @mock.patch.object(trex_stl_packet_builder_scapy, 'STLPktBuilder', + return_value='packet') + def test__create_single_packet(self, mock_pktbuilder): + size = 128 + rfc2544_profile = rfc2544.RFC2544Profile(self.TRAFFIC_PROFILE) + rfc2544_profile.ether_packet = Pkt.Eth() + rfc2544_profile.ip_packet = Pkt.IP() + rfc2544_profile.udp_packet = Pkt.UDP() + rfc2544_profile.trex_vm = 'trex_vm' + base_pkt = (rfc2544_profile.ether_packet / rfc2544_profile.ip_packet / + rfc2544_profile.udp_packet) + pad = (size - len(base_pkt)) * 'x' + output = rfc2544_profile._create_single_packet(size=size) + mock_pktbuilder.assert_called_once_with(pkt=base_pkt / pad, + vm='trex_vm') + self.assertEqual(output, 'packet') - def test_get_drop_percentage_div_zero(self): - traffic_generator = mock.Mock(autospec=TrexProfile) - traffic_generator.networks = { - "uplink_0": ["xe0"], - "downlink_0": ["xe1"], - } - traffic_generator.client = \ - mock.Mock(return_value=True) - r_f_c2544_profile = RFC2544Profile(self.TRAFFIC_PROFILE) - r_f_c2544_profile.params = self.PROFILE - self.assertIsNone( - r_f_c2544_profile.execute_traffic(traffic_generator)) - samples = {} - for ifname in range(1): - name = "xe{}".format(ifname) - samples[name] = {"rx_throughput_fps": 20, - "tx_throughput_fps": 20, - "rx_throughput_mbps": 10, - "tx_throughput_mbps": 10, - "in_packets": 1000, - "out_packets": 0} - r_f_c2544_profile.throughput_max = 0 - expected = { - 'DropPercentage': 100.0, 'RxThroughput': 100 / 3.0, - 'TxThroughput': 0.0, 'CurrentDropPercentage': 100.0, - 'Throughput': 66.66666666666667, - 'xe0': { - 'tx_throughput_fps': 20, 'in_packets': 1000, - 'out_packets': 0, 'rx_throughput_mbps': 10, - 'tx_throughput_mbps': 10, 'rx_throughput_fps': 20 - } - } - traffic_generator.generate_samples = mock.Mock(return_value=samples) - traffic_generator.RUN_DURATION = 30 - traffic_generator.rfc2544_helper.tolerance_low = 0.0001 - traffic_generator.rfc2544_helper.tolerance_high = 0.0001 - self.assertDictEqual(expected, - r_f_c2544_profile.get_drop_percentage(traffic_generator)) + @mock.patch.object(trex_stl_packet_builder_scapy, 'STLPktBuilder', + return_value='packet') + def test__create_single_packet_qinq(self, mock_pktbuilder): + size = 128 + rfc2544_profile = rfc2544.RFC2544Profile(self.TRAFFIC_PROFILE) + rfc2544_profile.ether_packet = Pkt.Eth() + rfc2544_profile.ip_packet = Pkt.IP() + rfc2544_profile.udp_packet = Pkt.UDP() + rfc2544_profile.trex_vm = 'trex_vm' + rfc2544_profile.qinq = True + rfc2544_profile.qinq_packet = Pkt.Dot1Q(vlan=1) / Pkt.Dot1Q(vlan=2) + base_pkt = (rfc2544_profile.ether_packet / + rfc2544_profile.qinq_packet / rfc2544_profile.ip_packet / + rfc2544_profile.udp_packet) + pad = (size - len(base_pkt)) * 'x' + output = rfc2544_profile._create_single_packet(size=size) + mock_pktbuilder.assert_called_once_with(pkt=base_pkt / pad, + vm='trex_vm') + self.assertEqual(output, 'packet') + + @mock.patch.object(trex_stl_streams, 'STLFlowLatencyStats') + @mock.patch.object(trex_stl_streams, 'STLTXCont') + @mock.patch.object(trex_stl_client, 'STLStream') + def test__create_streams(self, mock_stream, mock_txcont, mock_latency): + imix_data = {'64': 25, '512': 75} + rate = 35 + port_pg_id = rfc2544.PortPgIDMap() + port_pg_id.add_port(10) + mock_stream.side_effect = ['stream1', 'stream2'] + mock_txcont.side_effect = ['txcont1', 'txcont2'] + mock_latency.side_effect = ['latency1', 'latency2'] + rfc2544_profile = rfc2544.RFC2544Profile(self.TRAFFIC_PROFILE) + with mock.patch.object(rfc2544_profile, '_create_single_packet'): + output = rfc2544_profile._create_streams(imix_data, rate, + port_pg_id) + self.assertEqual(['stream1', 'stream2'], output) + mock_latency.assert_has_calls([ + mock.call(pg_id=1), mock.call(pg_id=2)]) + mock_txcont.assert_has_calls([ + mock.call(percentage=float(25 * 35) / 100), + mock.call(percentage=float(75 * 35) / 100)], any_order=True) + + def test_get_drop_percentage(self): + rfc2544_profile = rfc2544.RFC2544Profile(self.TRAFFIC_PROFILE) + samples = [ + {'xe1': {'tx_throughput_fps': 100, + 'rx_throughput_fps': 101, + 'out_packets': 2000, + 'in_packets': 2010}, + 'xe2': {'tx_throughput_fps': 200, + 'rx_throughput_fps': 201, + 'out_packets': 4000, + 'in_packets': 4010}}, + {'xe1': {'tx_throughput_fps': 106, + 'rx_throughput_fps': 108, + 'out_packets': 2031, + 'in_packets': 2040, + 'latency': 'Latency1'}, + 'xe2': {'tx_throughput_fps': 203, + 'rx_throughput_fps': 215, + 'out_packets': 4025, + 'in_packets': 4040, + 'latency': 'Latency2'}} + ] + output = rfc2544_profile.get_drop_percentage(samples, 0, 0, False) + expected = {'DropPercentage': 0.3963, + 'Latency': {'xe1': 'Latency1', 'xe2': 'Latency2'}, + 'RxThroughput': 312.5, + 'TxThroughput': 304.5, + 'CurrentDropPercentage': 0.3963, + 'Rate': 100, + 'Throughput': 312.5} + self.assertEqual(expected, output) - def test_get_multiplier(self): - r_f_c2544_profile = RFC2544Profile(self.TRAFFIC_PROFILE) - r_f_c2544_profile.max_rate = 100 - r_f_c2544_profile.min_rate = 100 - self.assertEqual("1.0", r_f_c2544_profile.get_multiplier()) - def test_calculate_pps(self): - r_f_c2544_profile = RFC2544Profile(self.TRAFFIC_PROFILE) - r_f_c2544_profile.rate = 100 - r_f_c2544_profile.pps = 100 - samples = {'Throughput': 4549093.33} - self.assertEqual((2274546.67, 1.0), - r_f_c2544_profile.calculate_pps(samples)) +class PortPgIDMapTestCase(base.BaseUnitTestCase): - def test_create_single_stream(self): - r_f_c2544_profile = RFC2544Profile(self.TRAFFIC_PROFILE) - r_f_c2544_profile._create_single_packet = mock.MagicMock() - r_f_c2544_profile.pg_id = 1 - self.assertIsNotNone( - r_f_c2544_profile.create_single_stream(64, 2274546.67)) + def test_add_port(self): + port_pg_id_map = rfc2544.PortPgIDMap() + port_pg_id_map.add_port(10) + self.assertEqual(10, port_pg_id_map._last_port) + self.assertEqual([], port_pg_id_map._port_pg_id_map[10]) - def test_create_single_stream_no_pg_id(self): - r_f_c2544_profile = RFC2544Profile(self.TRAFFIC_PROFILE) - r_f_c2544_profile._create_single_packet = mock.MagicMock() - r_f_c2544_profile.pg_id = 0 - self.assertIsNotNone( - r_f_c2544_profile.create_single_stream(64, 2274546.67)) + def test_get_pg_ids(self): + port_pg_id_map = rfc2544.PortPgIDMap() + port_pg_id_map.add_port(10) + port_pg_id_map.increase_pg_id() + port_pg_id_map.increase_pg_id() + port_pg_id_map.add_port(20) + port_pg_id_map.increase_pg_id() + self.assertEqual([1, 2], port_pg_id_map.get_pg_ids(10)) + self.assertEqual([3], port_pg_id_map.get_pg_ids(20)) + self.assertEqual([], port_pg_id_map.get_pg_ids(30)) - def test_execute_latency(self): - traffic_generator = mock.Mock(autospec=TrexProfile) - traffic_generator.networks = { - "private_0": ["xe0"], - "public_0": ["xe1"], - } - traffic_generator.client = \ - mock.Mock(return_value=True) - r_f_c2544_profile = RFC2544Profile(self.TRAFFIC_PROFILE) - r_f_c2544_profile.params = self.PROFILE - r_f_c2544_profile.first_run = True - samples = {} - for ifname in range(1): - name = "xe{}".format(ifname) - samples[name] = {"rx_throughput_fps": 20, - "tx_throughput_fps": 20, - "rx_throughput_mbps": 10, - "tx_throughput_mbps": 10, - "in_packets": 1000, - "out_packets": 0} + def test_increase_pg_id_no_port(self): + port_pg_id_map = rfc2544.PortPgIDMap() + self.assertIsNone(port_pg_id_map.increase_pg_id()) - samples['Throughput'] = 4549093.33 - r_f_c2544_profile.calculate_pps = mock.Mock(return_value=[2274546.67, - 1.0]) + def test_increase_pg_id_last_port(self): + port_pg_id_map = rfc2544.PortPgIDMap() + port_pg_id_map.add_port(10) + self.assertEqual(1, port_pg_id_map.increase_pg_id()) + self.assertEqual([1], port_pg_id_map.get_pg_ids(10)) + self.assertEqual(10, port_pg_id_map._last_port) - self.assertIsNone(r_f_c2544_profile.execute_latency(traffic_generator, - samples)) + def test_increase_pg_id(self): + port_pg_id_map = rfc2544.PortPgIDMap() + port_pg_id_map.add_port(10) + port_pg_id_map.increase_pg_id() + self.assertEqual(2, port_pg_id_map.increase_pg_id(port=20)) + self.assertEqual([1], port_pg_id_map.get_pg_ids(10)) + self.assertEqual([2], port_pg_id_map.get_pg_ids(20)) + self.assertEqual(20, port_pg_id_map._last_port) diff --git a/yardstick/tests/unit/network_services/traffic_profile/test_trex_traffic_profile.py b/yardstick/tests/unit/network_services/traffic_profile/test_trex_traffic_profile.py index 5fe1b7326..628e85459 100644 --- a/yardstick/tests/unit/network_services/traffic_profile/test_trex_traffic_profile.py +++ b/yardstick/tests/unit/network_services/traffic_profile/test_trex_traffic_profile.py @@ -14,29 +14,12 @@ import ipaddress -import mock import six import unittest -from yardstick.tests import STL_MOCKS from yardstick.common import exceptions as y_exc - -STLClient = mock.MagicMock() -stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) -stl_patch.start() - -if stl_patch: - from yardstick.network_services.traffic_profile.base import TrafficProfile - from yardstick.network_services.traffic_profile.trex_traffic_profile import TrexProfile - from yardstick.network_services.traffic_profile.trex_traffic_profile import SRC - from yardstick.network_services.traffic_profile.trex_traffic_profile import DST - from yardstick.network_services.traffic_profile.trex_traffic_profile import ETHERNET - from yardstick.network_services.traffic_profile.trex_traffic_profile import IP - from yardstick.network_services.traffic_profile.trex_traffic_profile import IPv6 - from yardstick.network_services.traffic_profile.trex_traffic_profile import UDP - from yardstick.network_services.traffic_profile.trex_traffic_profile import SRC_PORT - from yardstick.network_services.traffic_profile.trex_traffic_profile import DST_PORT - from yardstick.network_services.traffic_profile.trex_traffic_profile import TYPE_OF_SERVICE +from yardstick.network_services.traffic_profile import base as tp_base +from yardstick.network_services.traffic_profile import trex_traffic_profile class TestTrexProfile(unittest.TestCase): @@ -59,7 +42,7 @@ class TestTrexProfile(unittest.TestCase): 'name': 'rfc2544', 'traffic_profile': {'traffic_type': 'RFC2544Profile', 'frame_rate': 100}, - TrafficProfile.DOWNLINK: { + tp_base.TrafficProfile.DOWNLINK: { 'ipv4': {'outer_l2': {'framesize': {'64B': '100', '1518B': '0', '128B': '0', @@ -77,7 +60,7 @@ class TestTrexProfile(unittest.TestCase): 'outer_l4': {'srcport': '2001', 'dsrport': '1234', 'count': 1}}}, - TrafficProfile.UPLINK: { + tp_base.TrafficProfile.UPLINK: { 'ipv4': {'outer_l2': {'framesize': {'64B': '100', '1518B': '0', @@ -99,7 +82,7 @@ class TestTrexProfile(unittest.TestCase): 'name': 'rfc2544', 'traffic_profile': {'traffic_type': 'RFC2544Profile', 'frame_rate': 100}, - TrafficProfile.DOWNLINK: { + tp_base.TrafficProfile.DOWNLINK: { 'ipv6': {'outer_l2': {'framesize': {'64B': '100', '1518B': '0', '128B': '0', '1400B': '0', @@ -118,7 +101,7 @@ class TestTrexProfile(unittest.TestCase): 'outer_l4': {'srcport': '2001', 'dsrport': '1234', 'count': 1}}}, - TrafficProfile.UPLINK: { + tp_base.TrafficProfile.UPLINK: { 'ipv6': {'outer_l2': {'framesize': {'64B': '100', '1518B': '0', '128B': '0', '1400B': '0', @@ -140,17 +123,15 @@ class TestTrexProfile(unittest.TestCase): 'schema': 'isb:traffic_profile:0.1'} def test___init__(self): - TrafficProfile.params = self.PROFILE - trex_profile = \ - TrexProfile(TrafficProfile) + trex_profile = trex_traffic_profile.TrexProfile(self.PROFILE) self.assertEqual(trex_profile.pps, 100) def test_qinq(self): + trex_profile = trex_traffic_profile.TrexProfile(self.PROFILE) qinq = {"S-VLAN": {"id": 128, "priority": 0, "cfi": 0}, "C-VLAN": {"id": 512, "priority": 0, "cfi": 0}} - trex_profile = \ - TrexProfile(TrafficProfile) + trex_profile = trex_traffic_profile.TrexProfile(self.PROFILE) self.assertIsNone(trex_profile.set_qinq(qinq)) qinq = {"S-VLAN": {"id": "128-130", "priority": 0, "cfi": 0}, @@ -158,64 +139,39 @@ class TestTrexProfile(unittest.TestCase): self.assertIsNone(trex_profile.set_qinq(qinq)) def test__set_outer_l2_fields(self): - trex_profile = \ - TrexProfile(TrafficProfile) + trex_profile = trex_traffic_profile.TrexProfile(self.PROFILE) qinq = {"S-VLAN": {"id": 128, "priority": 0, "cfi": 0}, "C-VLAN": {"id": 512, "priority": 0, "cfi": 0}} - outer_l2 = self.PROFILE[TrafficProfile.UPLINK]['ipv4']['outer_l2'] + outer_l2 = self.PROFILE[ + tp_base.TrafficProfile.UPLINK]['ipv4']['outer_l2'] outer_l2['QinQ'] = qinq self.assertIsNone(trex_profile._set_outer_l2_fields(outer_l2)) def test__set_outer_l3v4_fields(self): - trex_profile = \ - TrexProfile(TrafficProfile) - outer_l3v4 = self.PROFILE[TrafficProfile.UPLINK]['ipv4']['outer_l3v4'] + trex_profile = trex_traffic_profile.TrexProfile(self.PROFILE) + outer_l3v4 = self.PROFILE[ + tp_base.TrafficProfile.UPLINK]['ipv4']['outer_l3v4'] outer_l3v4['proto'] = 'tcp' self.assertIsNone(trex_profile._set_outer_l3v4_fields(outer_l3v4)) def test__set_outer_l3v6_fields(self): - trex_profile = \ - TrexProfile(TrafficProfile) - outer_l3v6 = self.PROFILE_v6[TrafficProfile.UPLINK]['ipv6']['outer_l3v4'] + trex_profile = trex_traffic_profile.TrexProfile(self.PROFILE) + outer_l3v6 = self.PROFILE_v6[ + tp_base.TrafficProfile.UPLINK]['ipv6']['outer_l3v4'] outer_l3v6['proto'] = 'tcp' outer_l3v6['tc'] = 1 outer_l3v6['hlim'] = 10 self.assertIsNone(trex_profile._set_outer_l3v6_fields(outer_l3v6)) def test__set_outer_l4_fields(self): - trex_profile = \ - TrexProfile(TrafficProfile) - outer_l4 = self.PROFILE[TrafficProfile.UPLINK]['ipv4']['outer_l4'] + trex_profile = trex_traffic_profile.TrexProfile(self.PROFILE) + outer_l4 = self.PROFILE[ + tp_base.TrafficProfile.UPLINK]['ipv4']['outer_l4'] self.assertIsNone(trex_profile._set_outer_l4_fields(outer_l4)) - def test_get_streams(self): - trex_profile = \ - TrexProfile(TrafficProfile) - trex_profile.params = self.PROFILE - profile_data = self.PROFILE[TrafficProfile.UPLINK] - self.assertIsNotNone(trex_profile.get_streams(profile_data)) - trex_profile.pg_id = 1 - self.assertIsNotNone(trex_profile.get_streams(profile_data)) - trex_profile.params = self.PROFILE_v6 - trex_profile.profile_data = self.PROFILE_v6[TrafficProfile.UPLINK] - self.assertIsNotNone(trex_profile.get_streams(profile_data)) - trex_profile.pg_id = 1 - self.assertIsNotNone(trex_profile.get_streams(profile_data)) - - def test_generate_packets(self): - trex_profile = \ - TrexProfile(TrafficProfile) - trex_profile.fsize = 10 - trex_profile.base_pkt = [10] - self.assertIsNone(trex_profile.generate_packets()) - - def test_generate_imix_data_error(self): - trex_profile = \ - TrexProfile(TrafficProfile) - self.assertEqual({}, trex_profile.generate_imix_data(False)) - def test__count_ip_ipv4(self): - start, end, count = TrexProfile._count_ip('1.1.1.1', '1.2.3.4') + start, end, count = trex_traffic_profile.TrexProfile._count_ip( + '1.1.1.1', '1.2.3.4') self.assertEqual('1.1.1.1', str(start)) self.assertEqual('1.2.3.4', str(end)) diff = (int(ipaddress.IPv4Address(six.u('1.2.3.4'))) - @@ -225,7 +181,8 @@ class TestTrexProfile(unittest.TestCase): def test__count_ip_ipv6(self): start_ip = '0064:ff9b:0:0:0:0:9810:6414' end_ip = '0064:ff9b:0:0:0:0:9810:6420' - start, end, count = TrexProfile._count_ip(start_ip, end_ip) + start, end, count = trex_traffic_profile.TrexProfile._count_ip( + start_ip, end_ip) self.assertEqual(0x98106414, start) self.assertEqual(0x98106420, end) self.assertEqual(0x98106420 - 0x98106414, count) @@ -234,10 +191,10 @@ class TestTrexProfile(unittest.TestCase): start_ip = '0064:ff9b:0:0:0:0:9810:6420' end_ip = '0064:ff9b:0:0:0:0:9810:6414' with self.assertRaises(y_exc.IPv6RangeError): - TrexProfile._count_ip(start_ip, end_ip) + trex_traffic_profile.TrexProfile._count_ip(start_ip, end_ip) def test__dscp_range_action_partial_actual_count_zero(self): - traffic_profile = TrexProfile(TrafficProfile) + traffic_profile = trex_traffic_profile.TrexProfile(self.PROFILE) dscp_partial = traffic_profile._dscp_range_action_partial() flow_vars_initial_length = len(traffic_profile.vm_flow_vars) @@ -245,7 +202,7 @@ class TestTrexProfile(unittest.TestCase): self.assertEqual(len(traffic_profile.vm_flow_vars), flow_vars_initial_length + 2) def test__dscp_range_action_partial_count_greater_than_actual(self): - traffic_profile = TrexProfile(TrafficProfile) + traffic_profile = trex_traffic_profile.TrexProfile(self.PROFILE) dscp_partial = traffic_profile._dscp_range_action_partial() flow_vars_initial_length = len(traffic_profile.vm_flow_vars) @@ -253,7 +210,7 @@ class TestTrexProfile(unittest.TestCase): self.assertEqual(len(traffic_profile.vm_flow_vars), flow_vars_initial_length + 2) def test__udp_range_action_partial_actual_count_zero(self): - traffic_profile = TrexProfile(TrafficProfile) + traffic_profile = trex_traffic_profile.TrexProfile(self.PROFILE) traffic_profile.udp['field1'] = 'value1' udp_partial = traffic_profile._udp_range_action_partial('field1') @@ -262,48 +219,59 @@ class TestTrexProfile(unittest.TestCase): self.assertEqual(len(traffic_profile.vm_flow_vars), flow_vars_initial_length + 2) def test__udp_range_action_partial_count_greater_than_actual(self): - traffic_profile = TrexProfile(TrafficProfile) + traffic_profile = trex_traffic_profile.TrexProfile(self.PROFILE) traffic_profile.udp['field1'] = 'value1' - udp_partial = traffic_profile._udp_range_action_partial('field1', 'not_used_count') - + udp_partial = traffic_profile._udp_range_action_partial( + 'field1', 'not_used_count') flow_vars_initial_length = len(traffic_profile.vm_flow_vars) udp_partial('1', '10', '100') self.assertEqual(len(traffic_profile.vm_flow_vars), flow_vars_initial_length + 2) def test__general_single_action_partial(self): - trex_profile = TrexProfile(TrafficProfile) - - trex_profile._general_single_action_partial(ETHERNET)(SRC)( + trex_profile = trex_traffic_profile.TrexProfile(self.PROFILE) + trex_profile._general_single_action_partial( + trex_traffic_profile.ETHERNET)(trex_traffic_profile.SRC)( self.EXAMPLE_ETHERNET_ADDR) self.assertEqual(self.EXAMPLE_ETHERNET_ADDR, trex_profile.ether_packet.src) - trex_profile._general_single_action_partial(IP)(DST)( - self.EXAMPLE_IP_ADDR) + trex_profile._general_single_action_partial(trex_traffic_profile.IP)( + trex_traffic_profile.DST)(self.EXAMPLE_IP_ADDR) self.assertEqual(self.EXAMPLE_IP_ADDR, trex_profile.ip_packet.dst) - trex_profile._general_single_action_partial(IPv6)(DST)( - self.EXAMPLE_IPv6_ADDR) + trex_profile._general_single_action_partial(trex_traffic_profile.IPv6)( + trex_traffic_profile.DST)(self.EXAMPLE_IPv6_ADDR) self.assertEqual(self.EXAMPLE_IPv6_ADDR, trex_profile.ip6_packet.dst) - trex_profile._general_single_action_partial(UDP)(SRC_PORT)(5060) + trex_profile._general_single_action_partial(trex_traffic_profile.UDP)( + trex_traffic_profile.SRC_PORT)(5060) self.assertEqual(5060, trex_profile.udp_packet.sport) - trex_profile._general_single_action_partial(IP)(TYPE_OF_SERVICE)(0) + trex_profile._general_single_action_partial(trex_traffic_profile.IP)( + trex_traffic_profile.TYPE_OF_SERVICE)(0) self.assertEqual(0, trex_profile.ip_packet.tos) def test__set_proto_addr(self): - trex_profile = TrexProfile(TrafficProfile) + trex_profile = trex_traffic_profile.TrexProfile(self.PROFILE) ether_range = "00:00:00:00:00:01-00:00:00:00:00:02" ip_range = "1.1.1.2-1.1.1.10" ipv6_range = '0064:ff9b:0:0:0:0:9810:6414-0064:ff9b:0:0:0:0:9810:6420' - trex_profile._set_proto_addr(ETHERNET, SRC, ether_range) - trex_profile._set_proto_addr(ETHERNET, DST, ether_range) - trex_profile._set_proto_addr(IP, SRC, ip_range) - trex_profile._set_proto_addr(IP, DST, ip_range) - trex_profile._set_proto_addr(IPv6, SRC, ipv6_range) - trex_profile._set_proto_addr(IPv6, DST, ipv6_range) - trex_profile._set_proto_addr(UDP, SRC_PORT, "5060-5090") - trex_profile._set_proto_addr(UDP, DST_PORT, "5060") + trex_profile._set_proto_addr(trex_traffic_profile.ETHERNET, + trex_traffic_profile.SRC, ether_range) + trex_profile._set_proto_addr(trex_traffic_profile.ETHERNET, + trex_traffic_profile.DST, ether_range) + trex_profile._set_proto_addr(trex_traffic_profile.IP, + trex_traffic_profile.SRC, ip_range) + trex_profile._set_proto_addr(trex_traffic_profile.IP, + trex_traffic_profile.DST, ip_range) + trex_profile._set_proto_addr(trex_traffic_profile.IPv6, + trex_traffic_profile.SRC, ipv6_range) + trex_profile._set_proto_addr(trex_traffic_profile.IPv6, + trex_traffic_profile.DST, ipv6_range) + trex_profile._set_proto_addr(trex_traffic_profile.UDP, + trex_traffic_profile.SRC_PORT, + '5060-5090') + trex_profile._set_proto_addr(trex_traffic_profile.UDP, + trex_traffic_profile.DST_PORT, '5060') diff --git a/yardstick/tests/unit/network_services/vnf_generic/__init__.py b/yardstick/tests/unit/network_services/vnf_generic/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/yardstick/tests/unit/network_services/vnf_generic/__init__.py diff --git a/tests/unit/network_services/vnf_generic/test_vnfdgen.py b/yardstick/tests/unit/network_services/vnf_generic/test_vnfdgen.py index 2ab14129b..55b1955bc 100644 --- a/tests/unit/network_services/vnf_generic/test_vnfdgen.py +++ b/yardstick/tests/unit/network_services/vnf_generic/test_vnfdgen.py @@ -13,11 +13,8 @@ # limitations under the License. # -# Unittest for yardstick.network_services.vnf_generic.vnfdgen - -from __future__ import absolute_import -import unittest from six.moves import range +import unittest from yardstick.common.yaml_loader import yaml_load from yardstick.network_services.vnf_generic import vnfdgen @@ -202,10 +199,10 @@ TRAFFIC_PROFILE_TPL = """ TRAFFIC_PROFILE = { UPLINK: [{"ipv4": {"outer_l2": - {"framesize": {"64B": '10', "128B": '10', - "256B": '10', "373B": '10', - "570B": '10', "1400B": '10', - "1518B": '40'}}}}]} + {"framesize": {"64B": '10', "128B": '10', + "256B": '10', "373B": '10', + "570B": '10', "1400B": '10', + "1518B": '40'}}}}]} class TestRender(unittest.TestCase): @@ -214,12 +211,14 @@ class TestRender(unittest.TestCase): tmpl = "{{ routing_table }}" self.assertEqual(vnfdgen.render(tmpl, routing_table=None), u'~') - self.assertEqual(yaml_load(vnfdgen.render(tmpl, routing_table=None)), None) + self.assertIsNone( + yaml_load(vnfdgen.render(tmpl, routing_table=None))) def test_render_unicode_dict(self): tmpl = "{{ routing_table }}" - self.assertEqual(yaml_load(vnfdgen.render(tmpl, **NODE_CFG)), NODE_CFG["routing_table"]) + self.assertEqual(yaml_load(vnfdgen.render( + tmpl, **NODE_CFG)), NODE_CFG["routing_table"]) class TestVnfdGen(unittest.TestCase): @@ -266,7 +265,6 @@ class TestVnfdGen(unittest.TestCase): d = {'0': 1, 0: 24, 'b': 2} self.assertRaises(AttributeError, vnfdgen.deepgetitem, d, 0) - def test_generate_tp_single_var(self): """ Function to verify traffic profile generation with imix """ diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/__init__.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/__init__.py diff --git a/tests/unit/network_services/vnf_generic/vnf/tc_baremetal_rfc2544_ipv4_1flow_64B.yaml b/yardstick/tests/unit/network_services/vnf_generic/vnf/tc_baremetal_rfc2544_ipv4_1flow_64B.yaml index fb1be35c1..fb1be35c1 100644 --- a/tests/unit/network_services/vnf_generic/vnf/tc_baremetal_rfc2544_ipv4_1flow_64B.yaml +++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/tc_baremetal_rfc2544_ipv4_1flow_64B.yaml diff --git a/tests/unit/network_services/vnf_generic/vnf/test_acl_vnf.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_acl_vnf.py index 2971b55eb..69a5fb484 100644 --- a/tests/unit/network_services/vnf_generic/vnf/test_acl_vnf.py +++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_acl_vnf.py @@ -11,24 +11,21 @@ # 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. -# import unittest import mock import os +import re +import copy -from tests.unit import STL_MOCKS -from tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh from yardstick.common import utils - - -STLClient = mock.MagicMock() -stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) -stl_patch.start() - -if stl_patch: - from yardstick.network_services.vnf_generic.vnf.acl_vnf import AclApproxVnf - from yardstick.network_services.nfvi.resource import ResourceProfile +from yardstick.common import exceptions +from yardstick.benchmark.contexts import base as ctx_base +from yardstick.network_services.vnf_generic.vnf import acl_vnf +from yardstick.network_services.vnf_generic.vnf.base import VnfdHelper +from yardstick.network_services.nfvi.resource import ResourceProfile +from yardstick.network_services.vnf_generic.vnf.acl_vnf import AclApproxSetupEnvSetupEnvHelper +from yardstick.tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh TEST_FILE_YAML = 'nsb_test_case.yaml' @@ -141,7 +138,7 @@ class TestAclApproxVnf(unittest.TestCase): 'ip': '1.2.1.1', 'interfaces': {'xe0': {'local_iface_name': 'ens513f0', - 'vld_id': AclApproxVnf.DOWNLINK, + 'vld_id': acl_vnf.AclApproxVnf.DOWNLINK, 'netmask': '255.255.255.0', 'local_ip': '152.16.40.20', 'dst_mac': '00:00:00:00:00:01', @@ -169,7 +166,7 @@ class TestAclApproxVnf(unittest.TestCase): 'ip': '1.2.1.1', 'interfaces': {'xe0': {'local_iface_name': 'ens785f0', - 'vld_id': AclApproxVnf.UPLINK, + 'vld_id': acl_vnf.AclApproxVnf.UPLINK, 'netmask': '255.255.255.0', 'local_ip': '152.16.100.20', 'dst_mac': '00:00:00:00:00:02', @@ -194,7 +191,7 @@ class TestAclApproxVnf(unittest.TestCase): 'ip': '1.2.1.1', 'interfaces': {'xe0': {'local_iface_name': 'ens786f0', - 'vld_id': AclApproxVnf.UPLINK, + 'vld_id': acl_vnf.AclApproxVnf.UPLINK, 'netmask': '255.255.255.0', 'local_ip': '152.16.100.19', 'dst_mac': '00:00:00:00:00:04', @@ -204,7 +201,7 @@ class TestAclApproxVnf(unittest.TestCase): 'vpci': '0000:05:00.0', 'dpdk_port_num': 0}, 'xe1': {'local_iface_name': 'ens786f1', - 'vld_id': AclApproxVnf.DOWNLINK, + 'vld_id': acl_vnf.AclApproxVnf.DOWNLINK, 'netmask': '255.255.255.0', 'local_ip': '152.16.40.19', 'dst_mac': '00:00:00:00:00:03', @@ -240,22 +237,31 @@ class TestAclApproxVnf(unittest.TestCase): def test___init__(self, *args): vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - acl_approx_vnf = AclApproxVnf(name, vnfd) + acl_approx_vnf = acl_vnf.AclApproxVnf(name, vnfd, 'task_id') self.assertIsNone(acl_approx_vnf._vnf_process) @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.time") + @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', return_value='mock_node') @mock.patch(SSH_HELPER) def test_collect_kpi(self, ssh, *args): mock_ssh(ssh) vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - acl_approx_vnf = AclApproxVnf(name, vnfd) + acl_approx_vnf = acl_vnf.AclApproxVnf(name, vnfd, 'task_id') + acl_approx_vnf.scenario_helper.scenario_cfg = { + 'nodes': {acl_approx_vnf.name: "mock"} + } acl_approx_vnf.q_in = mock.MagicMock() acl_approx_vnf.q_out = mock.MagicMock() acl_approx_vnf.q_out.qsize = mock.Mock(return_value=0) acl_approx_vnf.resource = mock.Mock(autospec=ResourceProfile) acl_approx_vnf.vnf_execute = mock.Mock(return_value="") - result = {'packets_dropped': 0, 'packets_fwd': 0, 'packets_in': 0} + result = { + 'physical_node': 'mock_node', + 'packets_dropped': 0, + 'packets_fwd': 0, + 'packets_in': 0 + } self.assertEqual(result, acl_approx_vnf.collect_kpi()) @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.time") @@ -264,7 +270,7 @@ class TestAclApproxVnf(unittest.TestCase): mock_ssh(ssh) vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - acl_approx_vnf = AclApproxVnf(name, vnfd) + acl_approx_vnf = acl_vnf.AclApproxVnf(name, vnfd, 'task_id') acl_approx_vnf.q_in = mock.MagicMock() acl_approx_vnf.q_out = mock.MagicMock() acl_approx_vnf.q_out.qsize = mock.Mock(return_value=0) @@ -276,7 +282,7 @@ class TestAclApproxVnf(unittest.TestCase): mock_ssh(ssh) vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - acl_approx_vnf = AclApproxVnf(name, vnfd) + acl_approx_vnf = acl_vnf.AclApproxVnf(name, vnfd, 'task_id') acl_approx_vnf.q_in = mock.MagicMock() acl_approx_vnf.q_out = mock.MagicMock() acl_approx_vnf.q_out.qsize = mock.Mock(return_value=0) @@ -297,7 +303,7 @@ class TestAclApproxVnf(unittest.TestCase): mock_ssh(ssh) vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - acl_approx_vnf = AclApproxVnf(name, vnfd) + acl_approx_vnf = acl_vnf.AclApproxVnf(name, vnfd, 'task_id') acl_approx_vnf._build_config = mock.MagicMock() acl_approx_vnf.queue_wrapper = mock.MagicMock() acl_approx_vnf.scenario_helper.scenario_cfg = self.scenario_cfg @@ -310,7 +316,6 @@ class TestAclApproxVnf(unittest.TestCase): acl_approx_vnf._run() acl_approx_vnf.ssh_helper.run.assert_called_once() - @mock.patch("yardstick.network_services.vnf_generic.vnf.acl_vnf.YangModel") @mock.patch.object(utils, 'find_relative_file') @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.Context") @mock.patch(SSH_HELPER) @@ -318,12 +323,12 @@ class TestAclApproxVnf(unittest.TestCase): mock_ssh(ssh) vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - acl_approx_vnf = AclApproxVnf(name, vnfd) + acl_approx_vnf = acl_vnf.AclApproxVnf(name, vnfd, 'task_id') acl_approx_vnf.deploy_helper = mock.MagicMock() acl_approx_vnf.resource_helper = mock.MagicMock() acl_approx_vnf._build_config = mock.MagicMock() self.scenario_cfg['vnf_options'] = {'acl': {'cfg': "", - 'rules': ""}} + 'rules': ""}} acl_approx_vnf.q_out.put("pipeline>") acl_approx_vnf.WAIT_TIME = 0 self.scenario_cfg.update({"nodes": {"vnf__1": ""}}) @@ -336,7 +341,7 @@ class TestAclApproxVnf(unittest.TestCase): mock_ssh(ssh) vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - acl_approx_vnf = AclApproxVnf(name, vnfd) + acl_approx_vnf = acl_vnf.AclApproxVnf(name, vnfd, 'task_id') acl_approx_vnf._vnf_process = mock.MagicMock() acl_approx_vnf._vnf_process.terminate = mock.Mock() acl_approx_vnf.used_drivers = {"01:01.0": "i40e", @@ -345,3 +350,169 @@ class TestAclApproxVnf(unittest.TestCase): acl_approx_vnf.dpdk_devbind = "dpdk-devbind.py" acl_approx_vnf._resource_collect_stop = mock.Mock() self.assertIsNone(acl_approx_vnf.terminate()) + + +class TestAclApproxSetupEnvSetupEnvHelper(unittest.TestCase): + + ACL_CONFIG = {"access-list-entries": [{ + "actions": [ + "count", + {"fwd": { + "port": 0 + } + } + ], + "matches": { + "destination-ipv4-network": "152.16.0.0/24", + "destination-port-range": { + "lower-port": 0, + "upper-port": 65535 + }, + "source-ipv4-network": "0.0.0.0/0", + "source-port-range": { + "lower-port": 0, + "upper-port": 65535 + }, + "protocol-mask": 255, + "protocol": 127, + "priority": 1 + }, + "rule-name": "rule1588" + } + ]} + + def test_get_default_flows(self): + """Check if default ACL SampleVNF CLI commands are + generated correctly""" + ssh_helper = mock.Mock() + vnfd_helper = VnfdHelper({'vdu': [ + {'external-interface': [ + { + 'virtual-interface': { + 'local_ip': '152.16.100.19', + 'netmask': '255.255.255.0', + 'dpdk_port_num': 0, + 'dst_ip': '152.16.100.20', + 'vld_id': 'uplink_0', + 'ifname': 'xe0', + }, + 'vnfd-connection-point-ref': 'xe0', + 'name': 'xe0' + }, + { + 'virtual-interface': { + 'local_ip': '152.16.40.19', + 'netmask': '255.255.255.0', + 'dpdk_port_num': 1, + 'dst_ip': '152.16.40.20', + 'vld_id': 'downlink_0', + 'ifname': 'xe1', + }, + 'vnfd-connection-point-ref': 'xe1', + 'name': 'xe1' + } + ]} + ]}) + setup_helper = AclApproxSetupEnvSetupEnvHelper(vnfd_helper, ssh_helper, None) + self.check_acl_commands(setup_helper.get_flows_config(), [ + # format: (<cli pattern>, <number of expected matches>) + ("^p action add [0-9]+ accept$", 2), + ("^p action add [0-9]+ count$", 2), + ("^p action add [0-9]+ fwd 1$", 1), + ("^p action add [0-9]+ fwd 0$", 1), + ("^p acl add 1 152.16.100.0 24 152.16.40.0 24 0 65535 0 65535 0 0 [0-9]+$", 1), + ("^p acl add 1 152.16.40.0 24 152.16.100.0 24 0 65535 0 65535 0 0 [0-9]+$", 1), + ("^p acl applyruleset$", 1) + ]) + + @mock.patch.object(AclApproxSetupEnvSetupEnvHelper, 'get_default_flows') + def test_get_flows_config(self, get_default_flows): + """Check if provided ACL config can be converted to + ACL SampleVNF CLI commands correctly""" + ssh_helper = mock.Mock() + setup_helper = AclApproxSetupEnvSetupEnvHelper(None, ssh_helper, None) + get_default_flows.return_value = ({}, []) + self.check_acl_commands(setup_helper.get_flows_config(self.ACL_CONFIG), [ + # format: (<cli pattern>, <number of expected matches>) + ("^p action add [0-9]+ count$", 1), + ("^p action add [0-9]+ fwd 0$", 1), + ("^p acl add 1 0.0.0.0 0 152.16.0.0 24 0 65535 0 65535 127 0 [0-9]+$", 1), + ("^p acl applyruleset$", 1) + ]) + + @mock.patch.object(AclApproxSetupEnvSetupEnvHelper, 'get_default_flows') + def test_get_flows_config_invalid_action(self, get_default_flows): + """Check if incorrect ACL config fails to convert + to ACL SampleVNF CLI commands""" + ssh_helper = mock.Mock() + setup_helper = AclApproxSetupEnvSetupEnvHelper(None, ssh_helper, None) + get_default_flows.return_value = ({}, []) + # duplicate config and add invald action + acl_config = copy.deepcopy(self.ACL_CONFIG) + acl_config['access-list-entries'][0]["actions"].append({"xnat": {}}) + self.assertRaises(exceptions.AclUnknownActionTemplate, + setup_helper.get_flows_config, acl_config) + + @mock.patch.object(AclApproxSetupEnvSetupEnvHelper, 'get_default_flows') + def test_get_flows_config_invalid_action_param(self, get_default_flows): + """Check if ACL config with invalid action parameter fails to convert + to ACL SampleVNF CLI commands""" + ssh_helper = mock.Mock() + setup_helper = AclApproxSetupEnvSetupEnvHelper(None, ssh_helper, None) + get_default_flows.return_value = ({}, []) + # duplicate config and add action with invalid parameter + acl_config = copy.deepcopy(self.ACL_CONFIG) + acl_config['access-list-entries'][0]["actions"].append( + {"nat": {"xport": 0}}) + self.assertRaises(exceptions.AclMissingActionArguments, + setup_helper.get_flows_config, acl_config) + + def check_acl_commands(self, config, expected_cli_patterns): + """Check if expected ACL CLI commands (given as a list of patterns, + `expected_cli_patterns` parameter) present in SampleVNF ACL + configuration (given as a multiline string, `config` parameter)""" + # Example of expected config: + # --------------------------- + # p action add 1 accept + # p action add 1 fwd 1 + # p action add 2 accept + # p action add 2 count + # p action add 2 fwd 0 + # p acl add 1 152.16.100.0 24 152.16.40.0 24 0 65535 0 65535 0 0 1 + # p acl add 1 152.16.40.0 24 152.16.100.0 24 0 65535 0 65535 0 0 2 + # p acl applyruleset + # --------------------------- + # NOTE: The config above consists of actions ids, which are actually + # unknown (generated at runtime), thus it's incorrect just to compare + # the example ACL config above with the configuration returned by + # get_flows_config() function. It's more correct to use CLI patterns + # (RE) to find the required SampleVNF CLI commands in the multiline + # string (SampleVNF ACL configuration). + for pattern, num_of_match in expected_cli_patterns: + # format: (<cli pattern>, <number of expected matches>) + result = re.findall(pattern, config, re.MULTILINE) + self.assertEqual(len(result), num_of_match) + + @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.open') + @mock.patch.object(utils, 'find_relative_file') + @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.MultiPortConfig') + @mock.patch.object(utils, 'open_relative_file') + def test_build_config(self, *args): + vnfd_helper = mock.Mock() + ssh_helper = mock.Mock() + scenario_helper = mock.Mock() + scenario_helper.vnf_cfg = {'lb_config': 'HW'} + scenario_helper.options = {} + scenario_helper.all_options = {} + + acl_approx_setup_helper = AclApproxSetupEnvSetupEnvHelper(vnfd_helper, + ssh_helper, + scenario_helper) + + acl_approx_setup_helper.get_flows_config = mock.Mock() + acl_approx_setup_helper.ssh_helper.provision_tool = mock.Mock(return_value='tool_path') + acl_approx_setup_helper.ssh_helper.all_ports = mock.Mock() + acl_approx_setup_helper.vnfd_helper.port_nums = mock.Mock(return_value=[0, 1]) + expected = 'sudo tool_path -p 0x3 -f /tmp/acl_config -s /tmp/acl_script --hwlb 3' + self.assertEqual(acl_approx_setup_helper.build_config(), expected) + acl_approx_setup_helper.get_flows_config.assert_called_once() diff --git a/tests/unit/network_services/vnf_generic/vnf/test_base.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_base.py index 9ef6473f0..2ea13a5e0 100644 --- a/tests/unit/network_services/vnf_generic/vnf/test_base.py +++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_base.py @@ -11,18 +11,21 @@ # 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.network_services.vnf_generic.vnf.test_base import multiprocessing import os +import uuid import mock +from oslo_config import cfg +import oslo_messaging import unittest +from yardstick.common import messaging +from yardstick.common.messaging import payloads from yardstick.network_services.vnf_generic.vnf import base from yardstick.ssh import SSH +from yardstick.tests.unit import base as ut_base IP_PIPELINE_CFG_FILE_TPL = ("arp_route_tbl = ({port0_local_ip_hex}," @@ -142,6 +145,24 @@ VNFD = { } +class _DummyGenericTrafficGen(base.GenericTrafficGen): # pragma: no cover + + def run_traffic(self, *args): + pass + + def terminate(self): + pass + + def collect_kpi(self): + pass + + def instantiate(self, *args): + pass + + def scale(self, flavor=''): + pass + + class FileAbsPath(object): def __init__(self, module_file): super(FileAbsPath, self).__init__() @@ -208,22 +229,23 @@ class TestQueueFileWrapper(unittest.TestCase): self.assertIsNotNone(queue_file_wrapper.q_out.empty()) -class TestGenericVNF(unittest.TestCase): +class TestGenericVNF(ut_base.BaseUnitTestCase): def test_definition(self): """Make sure that the abstract class cannot be instantiated""" with self.assertRaises(TypeError) as exc: # pylint: disable=abstract-class-instantiated - base.GenericVNF('vnf1', VNFD['vnfd:vnfd-catalog']['vnfd'][0]) + base.GenericVNF('vnf1', VNFD['vnfd:vnfd-catalog']['vnfd'][0], + 'task_id') - msg = ("Can't instantiate abstract class GenericVNF with abstract methods " - "collect_kpi, instantiate, scale, start_collect, " + msg = ("Can't instantiate abstract class GenericVNF with abstract " + "methods collect_kpi, instantiate, scale, start_collect, " "stop_collect, terminate, wait_for_instantiate") self.assertEqual(msg, str(exc.exception)) -class TestGenericTrafficGen(unittest.TestCase): +class GenericTrafficGenTestCase(ut_base.BaseUnitTestCase): def test_definition(self): """Make sure that the abstract class cannot be instantiated""" @@ -231,8 +253,96 @@ class TestGenericTrafficGen(unittest.TestCase): name = 'vnf1' with self.assertRaises(TypeError) as exc: # pylint: disable=abstract-class-instantiated - base.GenericTrafficGen(name, vnfd) + base.GenericTrafficGen(name, vnfd, 'task_id') msg = ("Can't instantiate abstract class GenericTrafficGen with " "abstract methods collect_kpi, instantiate, run_traffic, " "scale, terminate") self.assertEqual(msg, str(exc.exception)) + + def test_get_mq_producer_id(self): + vnfd = {'benchmark': {'kpi': mock.ANY}, + 'vdu': [{'external-interface': 'ext_int'}] + } + tg = _DummyGenericTrafficGen('name', vnfd, 'task_id') + tg._mq_producer = mock.Mock() + tg._mq_producer.id = 'fake_id' + self.assertEqual('fake_id', tg.get_mq_producer_id()) + + +class TrafficGeneratorProducerTestCase(ut_base.BaseUnitTestCase): + + @mock.patch.object(oslo_messaging, 'Target', return_value='rpc_target') + @mock.patch.object(oslo_messaging, 'RPCClient') + @mock.patch.object(oslo_messaging, 'get_rpc_transport', + return_value='rpc_transport') + @mock.patch.object(cfg, 'CONF') + def test__init(self, mock_config, mock_transport, mock_rpcclient, + mock_target): + _id = uuid.uuid1().int + tg_producer = base.TrafficGeneratorProducer(_id) + mock_transport.assert_called_once_with( + mock_config, url='rabbit://yardstick:yardstick@localhost:5672/') + mock_target.assert_called_once_with(topic=messaging.TOPIC_TG, + fanout=True, + server=messaging.SERVER) + mock_rpcclient.assert_called_once_with('rpc_transport', 'rpc_target') + self.assertEqual(_id, tg_producer._id) + self.assertEqual(messaging.TOPIC_TG, tg_producer._topic) + + @mock.patch.object(oslo_messaging, 'Target', return_value='rpc_target') + @mock.patch.object(oslo_messaging, 'RPCClient') + @mock.patch.object(oslo_messaging, 'get_rpc_transport', + return_value='rpc_transport') + @mock.patch.object(payloads, 'TrafficGeneratorPayload', + return_value='tg_pload') + def test_tg_method_started(self, mock_tg_payload, *args): + tg_producer = base.TrafficGeneratorProducer(uuid.uuid1().int) + with mock.patch.object(tg_producer, 'send_message') as mock_message: + tg_producer.tg_method_started(version=10) + + mock_message.assert_called_once_with(messaging.TG_METHOD_STARTED, + 'tg_pload') + mock_tg_payload.assert_called_once_with(version=10, iteration=0, + kpi={}) + + @mock.patch.object(oslo_messaging, 'Target', return_value='rpc_target') + @mock.patch.object(oslo_messaging, 'RPCClient') + @mock.patch.object(oslo_messaging, 'get_rpc_transport', + return_value='rpc_transport') + @mock.patch.object(payloads, 'TrafficGeneratorPayload', + return_value='tg_pload') + def test_tg_method_finished(self, mock_tg_payload, *args): + tg_producer = base.TrafficGeneratorProducer(uuid.uuid1().int) + with mock.patch.object(tg_producer, 'send_message') as mock_message: + tg_producer.tg_method_finished(version=20) + + mock_message.assert_called_once_with(messaging.TG_METHOD_FINISHED, + 'tg_pload') + mock_tg_payload.assert_called_once_with(version=20, iteration=0, + kpi={}) + + @mock.patch.object(oslo_messaging, 'Target', return_value='rpc_target') + @mock.patch.object(oslo_messaging, 'RPCClient') + @mock.patch.object(oslo_messaging, 'get_rpc_transport', + return_value='rpc_transport') + @mock.patch.object(payloads, 'TrafficGeneratorPayload', + return_value='tg_pload') + def test_tg_method_iteration(self, mock_tg_payload, *args): + tg_producer = base.TrafficGeneratorProducer(uuid.uuid1().int) + with mock.patch.object(tg_producer, 'send_message') as mock_message: + tg_producer.tg_method_iteration(100, version=30, kpi={'k': 'v'}) + + mock_message.assert_called_once_with(messaging.TG_METHOD_ITERATION, + 'tg_pload') + mock_tg_payload.assert_called_once_with(version=30, iteration=100, + kpi={'k': 'v'}) + + +class GenericVNFConsumerTestCase(ut_base.BaseUnitTestCase): + + def test__init(self): + endpoints = 'endpoint_1' + _ids = [uuid.uuid1().int] + gvnf_consumer = base.GenericVNFConsumer(_ids, endpoints) + self.assertEqual(_ids, gvnf_consumer._ids) + self.assertEqual([endpoints], gvnf_consumer._endpoints) diff --git a/tests/unit/network_services/vnf_generic/vnf/test_cgnapt_vnf.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_cgnapt_vnf.py index edaa0ad7e..32f5b758d 100644 --- a/tests/unit/network_services/vnf_generic/vnf/test_cgnapt_vnf.py +++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_cgnapt_vnf.py @@ -11,31 +11,22 @@ # 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. -# from copy import deepcopy -import os -import unittest -import mock - -from tests.unit import STL_MOCKS -from tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh +import time +import mock +import unittest -STLClient = mock.MagicMock() -stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) -stl_patch.start() +from yardstick.benchmark.contexts import base as ctx_base +from yardstick.common import utils +from yardstick.common import process +from yardstick.network_services.vnf_generic.vnf import cgnapt_vnf +from yardstick.network_services.vnf_generic.vnf import sample_vnf +from yardstick.network_services.nfvi import resource -if stl_patch: - from yardstick.network_services.vnf_generic.vnf.cgnapt_vnf import CgnaptApproxVnf, \ - CgnaptApproxSetupEnvHelper - from yardstick.network_services.vnf_generic.vnf import cgnapt_vnf - from yardstick.network_services.nfvi.resource import ResourceProfile TEST_FILE_YAML = 'nsb_test_case.yaml' -SSH_HELPER = 'yardstick.network_services.vnf_generic.vnf.sample_vnf.VnfSshHelper' - - name = 'vnf__0' @@ -43,8 +34,9 @@ class TestCgnaptApproxSetupEnvHelper(unittest.TestCase): def test__generate_ip_from_pool(self): - ip = CgnaptApproxSetupEnvHelper._generate_ip_from_pool("1.2.3.4") - self.assertEqual(next(ip), '1.2.3.4') + _ip = '1.2.3.4' + ip = cgnapt_vnf.CgnaptApproxSetupEnvHelper._generate_ip_from_pool(_ip) + self.assertEqual(next(ip), _ip) self.assertEqual(next(ip), '1.2.4.4') self.assertEqual(next(ip), '1.2.5.4') @@ -63,24 +55,48 @@ link 1 up """ header = "This is a header" - out = CgnaptApproxSetupEnvHelper._update_cgnat_script_file(header, sample.splitlines()) + out = cgnapt_vnf.CgnaptApproxSetupEnvHelper._update_cgnat_script_file( + header, sample.splitlines()) self.assertNotIn("This is a header", out) def test__get_cgnapt_config(self): vnfd_helper = mock.MagicMock() vnfd_helper.port_pairs.uplink_ports = [{"name": 'a'}, {"name": "b"}, {"name": "c"}] - helper = CgnaptApproxSetupEnvHelper(vnfd_helper, mock.Mock(), mock.Mock()) + helper = cgnapt_vnf.CgnaptApproxSetupEnvHelper( + vnfd_helper, mock.Mock(), mock.Mock()) result = helper._get_cgnapt_config() self.assertIsNotNone(result) def test_scale(self): - helper = CgnaptApproxSetupEnvHelper(mock.Mock(), mock.Mock(), mock.Mock()) + helper = cgnapt_vnf.CgnaptApproxSetupEnvHelper( + mock.Mock(), mock.Mock(), mock.Mock()) with self.assertRaises(NotImplementedError): helper.scale() - -@mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.Process") + @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.open') + @mock.patch.object(utils, 'find_relative_file') + @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.MultiPortConfig') + @mock.patch.object(utils, 'open_relative_file') + def test_build_config(self, *args): + vnfd_helper = mock.Mock() + ssh_helper = mock.Mock() + scenario_helper = mock.Mock() + scenario_helper.vnf_cfg = {'lb_config': 'HW'} + scenario_helper.options = {} + scenario_helper.all_options = {} + + cgnat_approx_setup_helper = cgnapt_vnf.CgnaptApproxSetupEnvHelper( + vnfd_helper, ssh_helper, scenario_helper) + + cgnat_approx_setup_helper.ssh_helper.provision_tool = mock.Mock(return_value='tool_path') + cgnat_approx_setup_helper.ssh_helper.all_ports = mock.Mock() + cgnat_approx_setup_helper.vnfd_helper.port_nums = mock.Mock(return_value=[0, 1]) + expected = 'sudo tool_path -p 0x3 -f /tmp/cgnapt_config -s /tmp/cgnapt_script --hwlb 3' + self.assertEqual(cgnat_approx_setup_helper.build_config(), expected) + + +@mock.patch.object(sample_vnf, 'Process') class TestCgnaptApproxVnf(unittest.TestCase): VNFD = {'vnfd:vnfd-catalog': {'vnfd': @@ -200,7 +216,7 @@ class TestCgnaptApproxVnf(unittest.TestCase): 'ip': '1.2.1.1', 'interfaces': {'xe0': {'local_iface_name': 'ens513f0', - 'vld_id': CgnaptApproxVnf.DOWNLINK, + 'vld_id': cgnapt_vnf.CgnaptApproxVnf.DOWNLINK, 'netmask': '255.255.255.0', 'local_ip': '152.16.40.20', 'dst_mac': '00:00:00:00:00:01', @@ -228,7 +244,7 @@ class TestCgnaptApproxVnf(unittest.TestCase): 'ip': '1.2.1.1', 'interfaces': {'xe0': {'local_iface_name': 'ens785f0', - 'vld_id': CgnaptApproxVnf.UPLINK, + 'vld_id': cgnapt_vnf.CgnaptApproxVnf.UPLINK, 'netmask': '255.255.255.0', 'local_ip': '152.16.100.20', 'dst_mac': '00:00:00:00:00:02', @@ -253,7 +269,7 @@ class TestCgnaptApproxVnf(unittest.TestCase): 'ip': '1.2.1.1', 'interfaces': {'xe0': {'local_iface_name': 'ens786f0', - 'vld_id': CgnaptApproxVnf.UPLINK, + 'vld_id': cgnapt_vnf.CgnaptApproxVnf.UPLINK, 'netmask': '255.255.255.0', 'local_ip': '152.16.100.19', 'dst_mac': '00:00:00:00:00:04', @@ -263,7 +279,7 @@ class TestCgnaptApproxVnf(unittest.TestCase): 'vpci': '0000:05:00.0', 'dpdk_port_num': 0}, 'xe1': {'local_iface_name': 'ens786f1', - 'vld_id': CgnaptApproxVnf.DOWNLINK, + 'vld_id': cgnapt_vnf.CgnaptApproxVnf.DOWNLINK, 'netmask': '255.255.255.0', 'local_ip': '152.16.40.19', 'dst_mac': '00:00:00:00:00:03', @@ -302,81 +318,68 @@ class TestCgnaptApproxVnf(unittest.TestCase): def test___init__(self, *args): vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - cgnapt_approx_vnf = CgnaptApproxVnf(name, vnfd) + cgnapt_approx_vnf = cgnapt_vnf.CgnaptApproxVnf(name, vnfd, 'task_id') self.assertIsNone(cgnapt_approx_vnf._vnf_process) - @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.time') - @mock.patch(SSH_HELPER) - def test_collect_kpi(self, ssh, *args): - mock_ssh(ssh) - + @mock.patch.object(process, 'check_if_process_failed') + @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', return_value='mock_node') + def test_collect_kpi(self, *args): vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - cgnapt_approx_vnf = CgnaptApproxVnf(name, vnfd) + cgnapt_approx_vnf = cgnapt_vnf.CgnaptApproxVnf(name, vnfd, 'task_id') + cgnapt_approx_vnf.scenario_helper.scenario_cfg = { + 'nodes': {cgnapt_approx_vnf.name: "mock"} + } cgnapt_approx_vnf._vnf_process = mock.MagicMock( **{"is_alive.return_value": True, "exitcode": None}) cgnapt_approx_vnf.q_in = mock.MagicMock() cgnapt_approx_vnf.q_out = mock.MagicMock() cgnapt_approx_vnf.q_out.qsize = mock.Mock(return_value=0) - cgnapt_approx_vnf.resource = mock.Mock(autospec=ResourceProfile) - result = {'packets_dropped': 0, 'packets_fwd': 0, 'packets_in': 0} - self.assertEqual(result, cgnapt_approx_vnf.collect_kpi()) - - @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.time') - @mock.patch(SSH_HELPER) - def test_vnf_execute_command(self, ssh, *args): - mock_ssh(ssh) - + cgnapt_approx_vnf.resource = mock.Mock( + autospec=resource.ResourceProfile) + result = { + 'physical_node': 'mock_node', + 'packets_dropped': 0, + 'packets_fwd': 0, + 'packets_in': 0 + } + with mock.patch.object(cgnapt_approx_vnf, 'get_stats', + return_value=''): + self.assertEqual(result, cgnapt_approx_vnf.collect_kpi()) + + @mock.patch.object(time, 'sleep') + def test_vnf_execute_command(self, *args): vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - cgnapt_approx_vnf = CgnaptApproxVnf(name, vnfd) - cgnapt_approx_vnf.q_in = mock.MagicMock() - cgnapt_approx_vnf.q_out = mock.MagicMock() + cgnapt_approx_vnf = cgnapt_vnf.CgnaptApproxVnf(name, vnfd, 'task_id') + cgnapt_approx_vnf.q_in = mock.Mock() + cgnapt_approx_vnf.q_out = mock.Mock() cgnapt_approx_vnf.q_out.qsize = mock.Mock(return_value=0) - cmd = "quit" - self.assertEqual("", cgnapt_approx_vnf.vnf_execute(cmd)) - - @mock.patch(SSH_HELPER) - def test_get_stats(self, ssh, *args): - mock_ssh(ssh) + self.assertEqual("", cgnapt_approx_vnf.vnf_execute('quit')) + def test_get_stats(self, *args): vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - cgnapt_approx_vnf = CgnaptApproxVnf(name, vnfd) - cgnapt_approx_vnf.q_in = mock.MagicMock() - cgnapt_approx_vnf.q_out = mock.MagicMock() - cgnapt_approx_vnf.q_out.qsize = mock.Mock(return_value=0) - result = \ - "CG-NAPT(.*\n)*Received 100, Missed 0, Dropped 0,Translated 100,ingress" - cgnapt_approx_vnf.vnf_execute = mock.Mock(return_value=result) - self.assertListEqual(list(result), list(cgnapt_approx_vnf.get_stats())) - - def _get_file_abspath(self, filename): - curr_path = os.path.dirname(os.path.abspath(__file__)) - file_path = os.path.join(curr_path, filename) - return file_path - - @mock.patch("yardstick.network_services.vnf_generic.vnf.cgnapt_vnf.hex") - @mock.patch("yardstick.network_services.vnf_generic.vnf.cgnapt_vnf.eval") - @mock.patch('yardstick.network_services.vnf_generic.vnf.cgnapt_vnf.open') - @mock.patch(SSH_HELPER) - def test_run_vcgnapt(self, ssh, *args): - mock_ssh(ssh) + cgnapt_approx_vnf = cgnapt_vnf.CgnaptApproxVnf(name, vnfd, 'task_id') + with mock.patch.object(cgnapt_approx_vnf, 'vnf_execute') as mock_exec: + mock_exec.return_value = 'output' + self.assertEqual('output', cgnapt_approx_vnf.get_stats()) + mock_exec.assert_called_once_with('p cgnapt stats') + + def test_run_vcgnapt(self, *args): vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - cgnapt_approx_vnf = CgnaptApproxVnf(name, vnfd) - cgnapt_approx_vnf._build_config = mock.MagicMock() - cgnapt_approx_vnf.queue_wrapper = mock.MagicMock() - cgnapt_approx_vnf.ssh_helper = mock.MagicMock() - cgnapt_approx_vnf.ssh_helper.run = mock.MagicMock() - cgnapt_approx_vnf.scenario_helper.scenario_cfg = self.scenario_cfg - cgnapt_approx_vnf._run() - cgnapt_approx_vnf.ssh_helper.run.assert_called_once() + cgnapt_approx_vnf = cgnapt_vnf.CgnaptApproxVnf(name, vnfd, 'task_id') + cgnapt_approx_vnf.ssh_helper = mock.Mock() + cgnapt_approx_vnf.setup_helper = mock.Mock() + with mock.patch.object(cgnapt_approx_vnf, '_build_config'), \ + mock.patch.object(cgnapt_approx_vnf, '_build_run_kwargs'): + cgnapt_approx_vnf._run() - @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.Context") - @mock.patch(SSH_HELPER) - def test_instantiate(self, ssh, *args): - mock_ssh(ssh) + cgnapt_approx_vnf.ssh_helper.run.assert_called_once() + cgnapt_approx_vnf.setup_helper.kill_vnf.assert_called_once() + @mock.patch.object(ctx_base.Context, 'get_context_from_server') + def test_instantiate(self, *args): vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - cgnapt_approx_vnf = CgnaptApproxVnf(name, vnfd) + cgnapt_approx_vnf = cgnapt_vnf.CgnaptApproxVnf(name, vnfd, 'task_id') cgnapt_approx_vnf.deploy_helper = mock.MagicMock() cgnapt_approx_vnf.resource_helper = mock.MagicMock() cgnapt_approx_vnf._build_config = mock.MagicMock() @@ -385,35 +388,25 @@ class TestCgnaptApproxVnf(unittest.TestCase): cgnapt_approx_vnf.q_out.put("pipeline>") cgnapt_vnf.WAIT_TIME = 3 self.scenario_cfg.update({"nodes": {"vnf__0": ""}}) - self.assertIsNone(cgnapt_approx_vnf.instantiate(self.scenario_cfg, - self.context_cfg)) - - @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.time") - @mock.patch(SSH_HELPER) - def test__vnf_up_post(self, ssh, *args): - mock_ssh(ssh) + with mock.patch.object(cgnapt_approx_vnf, '_start_vnf'): + self.assertIsNone(cgnapt_approx_vnf.instantiate( + self.scenario_cfg, self.context_cfg)) + @mock.patch.object(time, 'sleep') + def test__vnf_up_post(self, *args): vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] self.scenario_cfg['options'][name]['napt'] = 'static' - - cgnapt_approx_vnf = CgnaptApproxVnf(name, vnfd) - cgnapt_approx_vnf._vnf_process = mock.MagicMock() - cgnapt_approx_vnf._vnf_process.terminate = mock.Mock() - cgnapt_approx_vnf.vnf_execute = mock.MagicMock() + cgnapt_approx_vnf = cgnapt_vnf.CgnaptApproxVnf(name, vnfd, 'task_id') + cgnapt_approx_vnf.vnf_execute = mock.Mock() cgnapt_approx_vnf.scenario_helper.scenario_cfg = self.scenario_cfg - cgnapt_approx_vnf._resource_collect_stop = mock.Mock() - cgnapt_approx_vnf._vnf_up_post() - - @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.time") - @mock.patch(SSH_HELPER) - def test__vnf_up_post_short(self, ssh, *args): - mock_ssh(ssh) + with mock.patch.object(cgnapt_approx_vnf, 'setup_helper') as \ + mock_setup_helper: + mock_setup_helper._generate_ip_from_pool.return_value = ['ip1'] + mock_setup_helper._get_cgnapt_config.return_value = ['gw_ip1'] + cgnapt_approx_vnf._vnf_up_post() + def test__vnf_up_post_short(self, *args): vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - cgnapt_approx_vnf = CgnaptApproxVnf(name, vnfd) - cgnapt_approx_vnf._vnf_process = mock.MagicMock() - cgnapt_approx_vnf._vnf_process.terminate = mock.Mock() - cgnapt_approx_vnf.vnf_execute = mock.MagicMock() + cgnapt_approx_vnf = cgnapt_vnf.CgnaptApproxVnf(name, vnfd, 'task_id') cgnapt_approx_vnf.scenario_helper.scenario_cfg = self.scenario_cfg - cgnapt_approx_vnf._resource_collect_stop = mock.Mock() cgnapt_approx_vnf._vnf_up_post() diff --git a/tests/unit/network_services/vnf_generic/vnf/test_prox_helpers.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_prox_helpers.py index bc48f994c..3b095647c 100644 --- a/tests/unit/network_services/vnf_generic/vnf/test_prox_helpers.py +++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_prox_helpers.py @@ -11,7 +11,6 @@ # 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. -# from itertools import repeat, chain import os @@ -21,39 +20,21 @@ import time import mock 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 +from yardstick.network_services.vnf_generic.vnf import base as vnf_base +from yardstick.network_services.vnf_generic.vnf import prox_helpers +from yardstick.network_services.vnf_generic.vnf import sample_vnf -STLClient = mock.MagicMock() -stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) -stl_patch.start() - -if stl_patch: - from yardstick.network_services.vnf_generic.vnf.sample_vnf import ScenarioHelper - from yardstick.network_services.vnf_generic.vnf.prox_helpers import ProxSocketHelper - from yardstick.network_services.vnf_generic.vnf.prox_helpers import PacketDump - from yardstick.network_services.vnf_generic.vnf.prox_helpers import CoreSocketTuple - from yardstick.network_services.vnf_generic.vnf.prox_helpers import ProxTestDataTuple - from yardstick.network_services.vnf_generic.vnf.prox_helpers import ProxDpdkVnfSetupEnvHelper - from yardstick.network_services.vnf_generic.vnf.prox_helpers import TotStatsTuple - from yardstick.network_services.vnf_generic.vnf.prox_helpers import ProxDataHelper - from yardstick.network_services.vnf_generic.vnf.prox_helpers import ProxResourceHelper - from yardstick.network_services.vnf_generic.vnf.prox_helpers import ProxProfileHelper - from yardstick.network_services.vnf_generic.vnf.prox_helpers import ProxMplsProfileHelper - from yardstick.network_services.vnf_generic.vnf.prox_helpers import ProxBngProfileHelper - 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') + core_tuple = prox_helpers.CoreSocketTuple('core 5s6') self.assertEqual(core_tuple.core_id, 5) self.assertEqual(core_tuple.socket_id, 6) self.assertFalse(core_tuple.is_hyperthread()) - core_tuple = CoreSocketTuple('core 5s6h') + core_tuple = prox_helpers.CoreSocketTuple('core 5s6h') self.assertEqual(core_tuple.core_id, 5) self.assertEqual(core_tuple.socket_id, 6) self.assertTrue(core_tuple.is_hyperthread()) @@ -81,7 +62,7 @@ class TestCoreTuple(unittest.TestCase): for bad_input in bad_inputs: with self.assertRaises(ValueError): - CoreSocketTuple(bad_input) + prox_helpers.CoreSocketTuple(bad_input) def test_find_in_topology(self): topology_in = { @@ -93,20 +74,20 @@ class TestCoreTuple(unittest.TestCase): }, } - core_tuple = CoreSocketTuple('core 5s6') + core_tuple = prox_helpers.CoreSocketTuple('core 5s6') expected = 'a' result = core_tuple.find_in_topology(topology_in) self.assertEqual(result, expected) - core_tuple = CoreSocketTuple('core 5s6h') + core_tuple = prox_helpers.CoreSocketTuple('core 5s6h') expected = 'c' result = core_tuple.find_in_topology(topology_in) self.assertEqual(result, expected) def test_find_in_topology_negative(self): - core_tuple = CoreSocketTuple('core 6s5') + core_tuple = prox_helpers.CoreSocketTuple('core 6s5') with self.assertRaises(ValueError): # no socket key core_tuple.find_in_topology({}) @@ -119,7 +100,7 @@ class TestCoreTuple(unittest.TestCase): # no first value (as needed by non-hyperthread core) core_tuple.find_in_topology({5: {6: {'key1': []}}}) - core_tuple = CoreSocketTuple('core 6s5h') + core_tuple = prox_helpers.CoreSocketTuple('core 6s5h') with self.assertRaises(ValueError): # no second value (as needed by hyperthread core) core_tuple.find_in_topology({5: {6: {'key1': ['e']}}}) @@ -129,20 +110,21 @@ class TestTotStatsTuple(unittest.TestCase): def test___new___negative(self): with self.assertRaises(TypeError): # no values - TotStatsTuple() + prox_helpers.TotStatsTuple() with self.assertRaises(TypeError): # one, non-integer value - TotStatsTuple('a') + prox_helpers.TotStatsTuple('a') with self.assertRaises(TypeError): # too many values - TotStatsTuple(3, 4, 5, 6, 7) + prox_helpers.TotStatsTuple(3, 4, 5, 6, 7) class TestProxTestDataTuple(unittest.TestCase): def test___init__(self): - prox_test_data = ProxTestDataTuple(1, 2, 3, 4, 5, 6, 7, 8, 9) + prox_test_data = prox_helpers.ProxTestDataTuple( + 1, 2, 3, 4, 5, 6, 7, 8, 9) self.assertEqual(prox_test_data.tolerated, 1) self.assertEqual(prox_test_data.tsc_hz, 2) self.assertEqual(prox_test_data.delta_rx, 3) @@ -151,32 +133,37 @@ class TestProxTestDataTuple(unittest.TestCase): self.assertEqual(prox_test_data.latency, 6) self.assertEqual(prox_test_data.rx_total, 7) self.assertEqual(prox_test_data.tx_total, 8) - self.assertEqual(prox_test_data.pps, 9) + self.assertEqual(prox_test_data.requested_pps, 9) def test_properties(self): - prox_test_data = ProxTestDataTuple(1, 2, 3, 4, 5, 6, 7, 8, 9) + prox_test_data = prox_helpers.ProxTestDataTuple( + 1, 2, 3, 4, 5, 6, 7, 8, 9) self.assertEqual(prox_test_data.pkt_loss, 12.5) - self.assertEqual(prox_test_data.mpps, 1.6 / 1e6) + self.assertEqual(prox_test_data.tx_mpps, 1.6 / 1e6) self.assertEqual(prox_test_data.can_be_lost, 0) self.assertEqual(prox_test_data.drop_total, 1) self.assertFalse(prox_test_data.success) - prox_test_data = ProxTestDataTuple(10, 2, 3, 4, 5, 6, 997, 998, 9) + prox_test_data = prox_helpers.ProxTestDataTuple( + 10, 2, 3, 4, 5, 6, 997, 998, 9) self.assertTrue(prox_test_data.success) def test_pkt_loss_zero_division(self): - prox_test_data = ProxTestDataTuple(1, 2, 3, 4, 5, 6, 7, 0, 9) + prox_test_data = prox_helpers.ProxTestDataTuple( + 1, 2, 3, 4, 5, 6, 7, 0, 9) self.assertEqual(prox_test_data.pkt_loss, 100.0) def test_get_samples(self): - prox_test_data = ProxTestDataTuple(1, 2, 3, 4, 5, [6.1, 6.9, 6.4], 7, 8, 9) + prox_test_data = prox_helpers.ProxTestDataTuple( + 1, 2, 3, 4, 5, [6.1, 6.9, 6.4], 7, 8, 9) expected = { - "Throughput": 1.6 / 1e6, + "Throughput": 1.2 / 1e6, "DropPackets": 12.5, "CurrentDropPackets": 12.5, - "TxThroughput": 9 / 1e6, - "RxThroughput": 1.6 / 1e6, + "RequestedTxThroughput": 9 / 1e6, + "TxThroughput": 1.6 / 1e6, + "RxThroughput": 1.2 / 1e6, "PktSize": 64, "PortSample": 1, "LatencyMin": 6.1, @@ -187,11 +174,12 @@ class TestProxTestDataTuple(unittest.TestCase): self.assertDictEqual(result, expected) expected = { - "Throughput": 1.6 / 1e6, + "Throughput": 1.2 / 1e6, "DropPackets": 0.123, "CurrentDropPackets": 0.123, - "TxThroughput": 9 / 1e6, - "RxThroughput": 1.6 / 1e6, + "RequestedTxThroughput": 9 / 1e6, + "TxThroughput": 1.6 / 1e6, + "RxThroughput": 1.2 / 1e6, "PktSize": 64, "LatencyMin": 6.1, "LatencyMax": 6.9, @@ -200,41 +188,44 @@ class TestProxTestDataTuple(unittest.TestCase): result = prox_test_data.get_samples(64, 0.123) self.assertDictEqual(result, expected) - @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.LOG') + @mock.patch('yardstick.LOG_RESULT', create=True) def test_log_data(self, mock_logger): my_mock_logger = mock.MagicMock() - prox_test_data = ProxTestDataTuple(1, 2, 3, 4, 5, [6.1, 6.9, 6.4], 7, 8, 9) + prox_test_data = prox_helpers.ProxTestDataTuple( + 1, 2, 3, 4, 5, [6.1, 6.9, 6.4], 7, 8, 9) prox_test_data.log_data() - self.assertEqual(my_mock_logger.debug.call_count, 0) - self.assertEqual(mock_logger.debug.call_count, 2) + + my_mock_logger.debug.assert_not_called() + mock_logger.debug.assert_not_called() mock_logger.debug.reset_mock() prox_test_data.log_data(my_mock_logger) - self.assertEqual(my_mock_logger.debug.call_count, 2) - self.assertEqual(mock_logger.debug.call_count, 0) + my_mock_logger.assert_not_called() + mock_logger.debug.assert_not_called() class TestPacketDump(unittest.TestCase): PAYLOAD = "payload" def test__init__(self): - PacketDump("port_id", len(self.PAYLOAD), self.PAYLOAD) + prox_helpers.PacketDump("port_id", len(self.PAYLOAD), self.PAYLOAD) def test___str__(self): expected = '<PacketDump port: port_id payload: {}>'.format(self.PAYLOAD) - dump1 = PacketDump("port_id", len(self.PAYLOAD), self.PAYLOAD) + dump1 = prox_helpers.PacketDump( + "port_id", len(self.PAYLOAD), self.PAYLOAD) self.assertEqual(str(dump1), expected) def test_port_id(self): - p = PacketDump("port_id", len(self.PAYLOAD), self.PAYLOAD) + p = prox_helpers.PacketDump("port_id", len(self.PAYLOAD), self.PAYLOAD) self.assertEqual(p.port_id, "port_id") def test_data_len(self): - p = PacketDump("port_id", len(self.PAYLOAD), self.PAYLOAD) + p = prox_helpers.PacketDump("port_id", len(self.PAYLOAD), self.PAYLOAD) self.assertEqual(p.data_len, len(self.PAYLOAD)) def test_payload(self): - p = PacketDump("port_id", len(self.PAYLOAD), self.PAYLOAD) + p = prox_helpers.PacketDump("port_id", len(self.PAYLOAD), self.PAYLOAD) self.assertEqual(p.payload(), self.PAYLOAD) self.assertEqual(p.payload(3), self.PAYLOAD[3:]) @@ -290,34 +281,40 @@ no data length value class TestProxSocketHelper(unittest.TestCase): def setUp(self): - self.mock_time_sleep = mock.patch.object(time, 'sleep').start() + self._mock_time_sleep = mock.patch.object(time, 'sleep') + self.mock_time_sleep = self._mock_time_sleep.start() + self.addCleanup(self._stop_mocks) + + def _stop_mocks(self): + self._mock_time_sleep.stop() - @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.socket') + @mock.patch.object(prox_helpers, 'socket') def test___init__(self, mock_socket): expected = mock_socket.socket() - prox = ProxSocketHelper() + prox = prox_helpers.ProxSocketHelper() result = prox._sock self.assertEqual(result, expected) def test_connect(self): mock_sock = mock.MagicMock() - prox = ProxSocketHelper(mock_sock) + prox = prox_helpers.ProxSocketHelper(mock_sock) prox.connect('10.20.30.40', 23456) - self.assertEqual(mock_sock.connect.call_count, 1) + mock_sock.connect.assert_called_once() def test_get_sock(self): mock_sock = mock.MagicMock() - prox = ProxSocketHelper(mock_sock) + prox = prox_helpers.ProxSocketHelper(mock_sock) result = prox.get_socket() self.assertIs(result, mock_sock) - @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.select') + # TODO(elfoley): Split this into three tests + @mock.patch.object(prox_helpers, 'select') def test_get_data(self, mock_select): mock_select.select.side_effect = [[1], [0]] mock_socket = mock.MagicMock() mock_recv = mock_socket.recv() mock_recv.decode.return_value = "" - prox = ProxSocketHelper(mock_socket) + prox = prox_helpers.ProxSocketHelper(mock_socket) ret = prox.get_data() self.assertEqual(ret, "") self.assertEqual(len(prox._pkt_dumps), 0) @@ -334,58 +331,58 @@ class TestProxSocketHelper(unittest.TestCase): mock_select.select.side_effect = chain([[object()], [None]], repeat([1], 3)) mock_recv.decode.return_value = PACKET_DUMP_2 ret = prox.get_data() - self.assertEqual(mock_select.select.call_count, 2) + self.assertEqual(mock_select.select.call_count, 1) self.assertEqual(ret, 'jumped over') self.assertEqual(len(prox._pkt_dumps), 3) def test__parse_socket_data_mixed_data(self): - prox = ProxSocketHelper(mock.MagicMock()) - ret = prox._parse_socket_data(PACKET_DUMP_NON_1, False) + prox = prox_helpers.ProxSocketHelper(mock.MagicMock()) + ret, _ = prox._parse_socket_data(PACKET_DUMP_NON_1, False) self.assertEqual(ret, 'not_a_dump,1,2') self.assertEqual(len(prox._pkt_dumps), 0) - ret = prox._parse_socket_data(PACKET_DUMP_MIXED_1, False) + ret, _ = prox._parse_socket_data(PACKET_DUMP_MIXED_1, False) self.assertEqual(ret, 'not_a_dump,1,2') self.assertEqual(len(prox._pkt_dumps), 1) def test__parse_socket_data_bad_data(self): - prox = ProxSocketHelper(mock.MagicMock()) + prox = prox_helpers.ProxSocketHelper(mock.MagicMock()) with self.assertRaises(ValueError): prox._parse_socket_data(PACKET_DUMP_BAD_1, False) with self.assertRaises(ValueError): prox._parse_socket_data(PACKET_DUMP_BAD_2, False) - ret = prox._parse_socket_data(PACKET_DUMP_BAD_3, False) + ret, _ = prox._parse_socket_data(PACKET_DUMP_BAD_3, False) self.assertEqual(ret, 'pktdump,3') def test__parse_socket_data_pkt_dump_only(self): - prox = ProxSocketHelper(mock.MagicMock()) - ret = prox._parse_socket_data('', True) + prox = prox_helpers.ProxSocketHelper(mock.MagicMock()) + ret, _ = prox._parse_socket_data('', True) self.assertFalse(ret) - ret = prox._parse_socket_data(PACKET_DUMP_1, True) + ret, _ = prox._parse_socket_data(PACKET_DUMP_1, True) self.assertTrue(ret) - ret = prox._parse_socket_data(PACKET_DUMP_2, True) + ret, _ = prox._parse_socket_data(PACKET_DUMP_2, True) self.assertTrue(ret) def test_put_command(self): mock_socket = mock.MagicMock() - prox = ProxSocketHelper(mock_socket) + prox = prox_helpers.ProxSocketHelper(mock_socket) prox.put_command("data") mock_socket.sendall.assert_called_once() def test_put_command_socket_error(self): mock_socket = mock.MagicMock() mock_socket.sendall.side_effect = OSError - prox = ProxSocketHelper(mock_socket) + prox = prox_helpers.ProxSocketHelper(mock_socket) prox.put_command("data") mock_socket.sendall.assert_called_once() def test_get_packet_dump(self): mock_socket = mock.MagicMock() - prox = ProxSocketHelper(mock_socket) + prox = prox_helpers.ProxSocketHelper(mock_socket) prox._pkt_dumps = [] self.assertIsNone(prox.get_packet_dump()) @@ -395,61 +392,61 @@ class TestProxSocketHelper(unittest.TestCase): def test_stop_all_reset(self): mock_socket = mock.MagicMock() - prox = ProxSocketHelper(mock_socket) + prox = prox_helpers.ProxSocketHelper(mock_socket) prox.stop_all_reset() mock_socket.sendall.assert_called() def test_stop_all(self): mock_socket = mock.MagicMock() - prox = ProxSocketHelper(mock_socket) + prox = prox_helpers.ProxSocketHelper(mock_socket) prox.stop_all() mock_socket.sendall.assert_called() def test_stop(self): mock_socket = mock.MagicMock() - prox = ProxSocketHelper(mock_socket) + prox = prox_helpers.ProxSocketHelper(mock_socket) prox.stop([3, 4, 5], 16) mock_socket.sendall.assert_called() def test_start_all(self): mock_socket = mock.MagicMock() - prox = ProxSocketHelper(mock_socket) + prox = prox_helpers.ProxSocketHelper(mock_socket) prox.start_all() mock_socket.sendall.assert_called() def test_start(self): mock_socket = mock.MagicMock() - prox = ProxSocketHelper(mock_socket) + prox = prox_helpers.ProxSocketHelper(mock_socket) prox.start([3, 4, 5]) mock_socket.sendall.assert_called() def test_reset_stats(self): mock_socket = mock.MagicMock() - prox = ProxSocketHelper(mock_socket) + prox = prox_helpers.ProxSocketHelper(mock_socket) prox.reset_stats() mock_socket.sendall.assert_called() def test_set_pkt_size(self): mock_socket = mock.MagicMock() - prox = ProxSocketHelper(mock_socket) + prox = prox_helpers.ProxSocketHelper(mock_socket) prox.set_pkt_size([3, 4, 5], 1024) self.assertEqual(mock_socket.sendall.call_count, 3) def test_set_value(self): mock_socket = mock.MagicMock() - prox = ProxSocketHelper(mock_socket) + prox = prox_helpers.ProxSocketHelper(mock_socket) prox.set_value([3, 4, 5], 10, 20, 30) self.assertEqual(mock_socket.sendall.call_count, 3) def test_reset_values(self): mock_socket = mock.MagicMock() - prox = ProxSocketHelper(mock_socket) + prox = prox_helpers.ProxSocketHelper(mock_socket) prox.reset_values([3, 4, 5]) self.assertEqual(mock_socket.sendall.call_count, 3) def test_set_speed(self): mock_socket = mock.MagicMock() - prox = ProxSocketHelper(mock_socket) + prox = prox_helpers.ProxSocketHelper(mock_socket) prox.set_speed([3, 4, 5], 1000) self.assertEqual(mock_socket.sendall.call_count, 3) @@ -466,7 +463,7 @@ class TestProxSocketHelper(unittest.TestCase): ] mock_socket = mock.MagicMock() - prox = ProxSocketHelper(mock_socket) + prox = prox_helpers.ProxSocketHelper(mock_socket) prox.set_speed = set_speed = mock.MagicMock() prox.slope_speed(core_data, 5) self.assertEqual(set_speed.call_count, 20) @@ -477,7 +474,7 @@ class TestProxSocketHelper(unittest.TestCase): def test_set_pps(self): mock_socket = mock.MagicMock() - prox = ProxSocketHelper(mock_socket) + prox = prox_helpers.ProxSocketHelper(mock_socket) prox.set_pps([3, 4, 5], 1000, 512) self.assertEqual(mock_socket.sendall.call_count, 3) @@ -491,7 +488,7 @@ class TestProxSocketHelper(unittest.TestCase): ] mock_socket = mock.MagicMock() - prox = ProxSocketHelper(mock_socket) + prox = prox_helpers.ProxSocketHelper(mock_socket) prox.get_data = mock.MagicMock(side_effect=latency_output) expected = ( @@ -514,7 +511,7 @@ class TestProxSocketHelper(unittest.TestCase): def test_get_all_tot_stats_error(self): mock_socket = mock.MagicMock() - prox = ProxSocketHelper(mock_socket) + prox = prox_helpers.ProxSocketHelper(mock_socket) prox.get_data = mock.MagicMock(return_value='3,4,5') expected = [0, 0, 0, 0] result = prox.get_all_tot_stats() @@ -522,7 +519,7 @@ class TestProxSocketHelper(unittest.TestCase): def test_get_all_tot_stats(self): mock_socket = mock.MagicMock() - prox = ProxSocketHelper(mock_socket) + prox = prox_helpers.ProxSocketHelper(mock_socket) prox.get_data = mock.MagicMock(return_value='3,4,5,6') expected = 3, 4, 5, 6 result = prox.get_all_tot_stats() @@ -530,7 +527,7 @@ class TestProxSocketHelper(unittest.TestCase): def test_hz(self): mock_socket = mock.MagicMock() - prox = ProxSocketHelper(mock_socket) + prox = prox_helpers.ProxSocketHelper(mock_socket) prox.get_data = mock.MagicMock(return_value='3,4,5,6') expected = 6 result = prox.hz() @@ -544,12 +541,37 @@ class TestProxSocketHelper(unittest.TestCase): ] mock_socket = mock.MagicMock() - prox = ProxSocketHelper(mock_socket) + prox = prox_helpers.ProxSocketHelper(mock_socket) prox.get_data = mock.MagicMock(side_effect=core_stats) expected = 21, 24, 27, 14 result = prox.core_stats([3, 4, 5], 16) self.assertEqual(result, expected) + @mock.patch.object(prox_helpers.LOG, 'error') + def test_multi_port_stats(self, *args): + mock_socket = mock.MagicMock() + prox = prox_helpers.ProxSocketHelper(mock_socket) + prox.get_data = mock.MagicMock(return_value='0,1,2,3,4,5;1,1,2,3,4,5') + expected = [[0, 1, 2, 3, 4, 5], [1, 1, 2, 3, 4, 5]] + result = prox.multi_port_stats([0, 1]) + self.assertEqual(result, expected) + + prox.get_data = mock.MagicMock(return_value='0,1,2,3,4,5;1,1,2,3,4,5') + result = prox.multi_port_stats([0]) + expected = [0] + self.assertEqual(result, expected) + + prox.get_data = mock.MagicMock(return_value='0,1,2,3;1,1,2,3,4,5') + result = prox.multi_port_stats([0, 1]) + expected = [0] * 2 + self.assertEqual(result, expected) + + prox.get_data = mock.MagicMock(return_value='99,1,2,3,4,5;1,1,2,3,4,5') + expected = [0] * 2 + result = prox.multi_port_stats([0, 1]) + self.assertEqual(result, expected) + + def test_port_stats(self): port_stats = [ ','.join(str(n) for n in range(3, 15)), @@ -558,7 +580,7 @@ class TestProxSocketHelper(unittest.TestCase): ] mock_socket = mock.MagicMock() - prox = ProxSocketHelper(mock_socket) + prox = prox_helpers.ProxSocketHelper(mock_socket) prox.get_data = mock.MagicMock(side_effect=port_stats) expected = [16, 26, 36, 46, 56, 66, 76, 86, 96, 106, 116, 126] result = prox.port_stats([3, 4, 5]) @@ -575,7 +597,7 @@ class TestProxSocketHelper(unittest.TestCase): ] mock_socket = mock.MagicMock() - prox = ProxSocketHelper(mock_socket) + prox = prox_helpers.ProxSocketHelper(mock_socket) prox.get_data = mock.MagicMock(side_effect=get_data_output) expected = { 'start_tot': start_tot, @@ -588,7 +610,7 @@ class TestProxSocketHelper(unittest.TestCase): def test_tot_stats(self): mock_socket = mock.MagicMock() - prox = ProxSocketHelper(mock_socket) + prox = prox_helpers.ProxSocketHelper(mock_socket) prox.get_data = mock.MagicMock(return_value='3,4,5,6') expected = 3, 4, 5 result = prox.tot_stats() @@ -596,7 +618,7 @@ class TestProxSocketHelper(unittest.TestCase): def test_tot_ierrors(self): mock_socket = mock.MagicMock() - prox = ProxSocketHelper(mock_socket) + prox = prox_helpers.ProxSocketHelper(mock_socket) prox.get_data = mock.MagicMock(return_value='3,4,5,6') expected = 3, 3 result = prox.tot_ierrors() @@ -604,25 +626,25 @@ class TestProxSocketHelper(unittest.TestCase): def test_set_count(self): mock_socket = mock.MagicMock() - prox = ProxSocketHelper(mock_socket) + prox = prox_helpers.ProxSocketHelper(mock_socket) prox.set_count(432, [3, 4, 5]) self.assertEqual(mock_socket.sendall.call_count, 3) def test_dump_rx(self): mock_socket = mock.MagicMock() - prox = ProxSocketHelper(mock_socket) + prox = prox_helpers.ProxSocketHelper(mock_socket) prox.dump_rx(3, 5, 8) - self.assertEqual(mock_socket.sendall.call_count, 1) + mock_socket.sendall.assert_called_once() def test_quit(self): mock_socket = mock.MagicMock() - prox = ProxSocketHelper(mock_socket) + prox = prox_helpers.ProxSocketHelper(mock_socket) prox.quit() mock_socket.sendall.assert_called() def test_force_quit(self): mock_socket = mock.MagicMock() - prox = ProxSocketHelper(mock_socket) + prox = prox_helpers.ProxSocketHelper(mock_socket) prox.force_quit() mock_socket.sendall.assert_called() @@ -734,8 +756,8 @@ class TestProxDpdkVnfSetupEnvHelper(unittest.TestCase): } def test_global_section(self): - setup_helper = ProxDpdkVnfSetupEnvHelper(mock.MagicMock(), mock.MagicMock(), - mock.MagicMock()) + setup_helper = prox_helpers.ProxDpdkVnfSetupEnvHelper( + mock.MagicMock(), mock.MagicMock(), mock.MagicMock()) setup_helper._prox_config_data = [('a', [])] @@ -783,8 +805,8 @@ class TestProxDpdkVnfSetupEnvHelper(unittest.TestCase): self.assertEqual(result, global_section[1]) def test_find_in_section(self): - setup_helper = ProxDpdkVnfSetupEnvHelper(mock.MagicMock(), mock.MagicMock(), - mock.MagicMock()) + setup_helper = prox_helpers.ProxDpdkVnfSetupEnvHelper( + mock.MagicMock(), mock.MagicMock(), mock.MagicMock()) setup_helper._prox_config_data = [ ('global', [ @@ -837,44 +859,51 @@ class TestProxDpdkVnfSetupEnvHelper(unittest.TestCase): # empty string input_str = '' expected = '' - result = ProxDpdkVnfSetupEnvHelper._replace_quoted_with_value(input_str, 'cat') + result = (prox_helpers.ProxDpdkVnfSetupEnvHelper. + _replace_quoted_with_value(input_str, 'cat')) self.assertEqual(result, expected) # no quoted substring input_str = 'lion tiger bear' expected = 'lion tiger bear' - result = ProxDpdkVnfSetupEnvHelper._replace_quoted_with_value(input_str, 'cat') + result = (prox_helpers.ProxDpdkVnfSetupEnvHelper. + _replace_quoted_with_value(input_str, 'cat')) self.assertEqual(result, expected) # partially quoted substring input_str = 'lion "tiger bear' expected = 'lion "tiger bear' - result = ProxDpdkVnfSetupEnvHelper._replace_quoted_with_value(input_str, 'cat') + result = (prox_helpers.ProxDpdkVnfSetupEnvHelper. + _replace_quoted_with_value(input_str, 'cat')) self.assertEqual(result, expected) # one quoted substring input_str = 'lion "tiger" bear' expected = 'lion "cat" bear' - result = ProxDpdkVnfSetupEnvHelper._replace_quoted_with_value(input_str, 'cat') + result = (prox_helpers.ProxDpdkVnfSetupEnvHelper. + _replace_quoted_with_value(input_str, 'cat')) self.assertEqual(result, expected) # two quoted substrings input_str = 'lion "tiger" bear "shark" whale' expected = 'lion "cat" bear "shark" whale' - result = ProxDpdkVnfSetupEnvHelper._replace_quoted_with_value(input_str, 'cat') + result = (prox_helpers.ProxDpdkVnfSetupEnvHelper. + _replace_quoted_with_value(input_str, 'cat')) self.assertEqual(result, expected) # two quoted substrings, both replaced input_str = 'lion "tiger" bear "shark" whale' expected = 'lion "cat" bear "cat" whale' - result = ProxDpdkVnfSetupEnvHelper._replace_quoted_with_value(input_str, 'cat', 2) + result = (prox_helpers.ProxDpdkVnfSetupEnvHelper. + _replace_quoted_with_value(input_str, 'cat', 2)) self.assertEqual(result, expected) def test__get_tx_port(self): # no data input_data = {'section1': []} expected = -1 - result = ProxDpdkVnfSetupEnvHelper._get_tx_port('section1', input_data) + result = (prox_helpers.ProxDpdkVnfSetupEnvHelper. + _get_tx_port('section1', input_data)) self.assertEqual(result, expected) # data for other section @@ -886,7 +915,8 @@ class TestProxDpdkVnfSetupEnvHelper(unittest.TestCase): ], } expected = -1 - result = ProxDpdkVnfSetupEnvHelper._get_tx_port('section1', input_data) + result = (prox_helpers.ProxDpdkVnfSetupEnvHelper. + _get_tx_port('section1', input_data)) self.assertEqual(result, expected) # data for section @@ -895,7 +925,8 @@ class TestProxDpdkVnfSetupEnvHelper(unittest.TestCase): ('tx port', '3'), ] expected = 3 - result = ProxDpdkVnfSetupEnvHelper._get_tx_port('section1', input_data) + result = (prox_helpers.ProxDpdkVnfSetupEnvHelper. + _get_tx_port('section1', input_data)) self.assertEqual(result, expected) # more data for section, @@ -904,13 +935,16 @@ class TestProxDpdkVnfSetupEnvHelper(unittest.TestCase): ('tx port', '1', 'and more', 234), ]) expected = 1 - result = ProxDpdkVnfSetupEnvHelper._get_tx_port('section1', input_data) + result = (prox_helpers.ProxDpdkVnfSetupEnvHelper. + _get_tx_port('section1', input_data)) self.assertEqual(result, expected) + # TODO(elfoley): Split this into several smaller tests def test_write_prox_config(self): input_data = {} expected = '' - result = ProxDpdkVnfSetupEnvHelper.write_prox_config(input_data) + result = (prox_helpers.ProxDpdkVnfSetupEnvHelper. + write_prox_config(input_data)) self.assertEqual(result, expected) input_data = [ @@ -920,7 +954,8 @@ class TestProxDpdkVnfSetupEnvHelper(unittest.TestCase): ], ] expected = '[section1]' - result = ProxDpdkVnfSetupEnvHelper.write_prox_config(input_data) + result = (prox_helpers.ProxDpdkVnfSetupEnvHelper. + write_prox_config(input_data)) self.assertEqual(result, expected) input_data = [ @@ -947,12 +982,13 @@ class TestProxDpdkVnfSetupEnvHelper(unittest.TestCase): 'key3=234', 'key4=multi-line\n\tvalue', ]) - result = ProxDpdkVnfSetupEnvHelper.write_prox_config(input_data) + result = (prox_helpers.ProxDpdkVnfSetupEnvHelper. + write_prox_config(input_data)) self.assertEqual(result, expected) def test_prox_config_data(self): - setup_helper = ProxDpdkVnfSetupEnvHelper(mock.MagicMock(), mock.MagicMock(), - mock.MagicMock()) + setup_helper = prox_helpers.ProxDpdkVnfSetupEnvHelper( + mock.MagicMock(), mock.MagicMock(), mock.MagicMock()) setup_helper.config_queue = config_queue = mock.MagicMock() config_queue.get.return_value = expected = [('s', [('a', 3), ('b', 45)])] @@ -973,7 +1009,7 @@ class TestProxDpdkVnfSetupEnvHelper(unittest.TestCase): vnfd_helper = mock.MagicMock() ssh_helper = mock.MagicMock() - scenario_helper = ScenarioHelper('vnf1') + scenario_helper = sample_vnf.ScenarioHelper('vnf1') scenario_helper.scenario_cfg = { 'task_path': 'a/b', 'options': { @@ -981,7 +1017,8 @@ class TestProxDpdkVnfSetupEnvHelper(unittest.TestCase): }, } - helper = ProxDpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper) + helper = prox_helpers.ProxDpdkVnfSetupEnvHelper( + vnfd_helper, ssh_helper, scenario_helper) helper.copy_to_target = mock.MagicMock(return_value='3') helper.generate_prox_config_file = mock.MagicMock(return_value='4') helper.upload_prox_config = mock.MagicMock(return_value='5') @@ -1007,7 +1044,7 @@ class TestProxDpdkVnfSetupEnvHelper(unittest.TestCase): mock_find_path.side_effect = ['1', '2'] vnfd_helper = mock.MagicMock() ssh_helper = mock.MagicMock() - scenario_helper = ScenarioHelper('vnf1') + scenario_helper = sample_vnf.ScenarioHelper('vnf1') scenario_helper.scenario_cfg = { 'task_path': 'a/b', 'options': { @@ -1016,7 +1053,8 @@ class TestProxDpdkVnfSetupEnvHelper(unittest.TestCase): } vnfd_helper.port_pairs.all_ports = ['xe0', 'xe1', 'xe2', 'xe3'] - helper = ProxDpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper) + helper = prox_helpers.ProxDpdkVnfSetupEnvHelper( + vnfd_helper, ssh_helper, scenario_helper) helper.copy_to_target = mock.MagicMock(side_effect=['33', '34', '35']) helper.generate_prox_config_file = mock.MagicMock(return_value='44') helper.upload_prox_config = mock.MagicMock(return_value='55') @@ -1042,7 +1080,7 @@ class TestProxDpdkVnfSetupEnvHelper(unittest.TestCase): mock_find_path.side_effect = ['1', '2'] + [str(i) for i in range(len(vnf1['prox_files']))] vnfd_helper = mock.MagicMock() ssh_helper = mock.MagicMock() - scenario_helper = ScenarioHelper('vnf1') + scenario_helper = sample_vnf.ScenarioHelper('vnf1') scenario_helper.scenario_cfg = { 'task_path': 'a/b', 'options': { @@ -1050,7 +1088,8 @@ class TestProxDpdkVnfSetupEnvHelper(unittest.TestCase): }, } - helper = ProxDpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper) + helper = prox_helpers.ProxDpdkVnfSetupEnvHelper( + vnfd_helper, ssh_helper, scenario_helper) helper.copy_to_target = mock.MagicMock(side_effect=['33', '34', '35']) helper.generate_prox_config_file = mock.MagicMock(return_value='44') helper.upload_prox_config = mock.MagicMock(return_value='55') @@ -1079,7 +1118,7 @@ class TestProxDpdkVnfSetupEnvHelper(unittest.TestCase): vnfd_helper = mock.Mock() ssh_helper = mock.Mock() ssh_helper.join_bin_path.return_value = '/opt/nsb_bin/prox' - scenario_helper = ScenarioHelper('vnf1') + scenario_helper = sample_vnf.ScenarioHelper('vnf1') scenario_helper.scenario_cfg = { 'task_path': 'a/b', 'options': { @@ -1090,8 +1129,8 @@ class TestProxDpdkVnfSetupEnvHelper(unittest.TestCase): expected = ("sudo bash -c 'cd /opt/nsb_bin; /opt/nsb_bin/prox -o cli " "-f -f /tmp/prox.cfg '") - helper = ProxDpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, - scenario_helper) + helper = prox_helpers.ProxDpdkVnfSetupEnvHelper( + vnfd_helper, ssh_helper, scenario_helper) with mock.patch.object(helper, 'build_config_file') as mock_cfg_file: helper.remote_path = '/tmp/prox.cfg' prox_cmd = helper.build_config() @@ -1103,7 +1142,8 @@ class TestProxDpdkVnfSetupEnvHelper(unittest.TestCase): ssh_helper = mock.MagicMock() scenario_helper = mock.MagicMock() - helper = ProxDpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper) + helper = prox_helpers.ProxDpdkVnfSetupEnvHelper( + vnfd_helper, ssh_helper, scenario_helper) helper.additional_files = {"ipv4.lua": "/tmp/ipv4.lua"} res = helper._insert_additional_file('dofile("ipv4.lua")') self.assertEqual(res, 'dofile("/tmp/ipv4.lua")') @@ -1119,11 +1159,12 @@ class TestProxDpdkVnfSetupEnvHelper(unittest.TestCase): mock_parser_type.side_effect = init - vnfd_helper = VnfdHelper(self.VNFD0) + vnfd_helper = vnf_base.VnfdHelper(self.VNFD0) ssh_helper = mock.MagicMock() scenario_helper = mock.MagicMock() - helper = ProxDpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper) + helper = prox_helpers.ProxDpdkVnfSetupEnvHelper( + vnfd_helper, ssh_helper, scenario_helper) helper.additional_files = {} expected = [] @@ -1208,7 +1249,8 @@ class TestProxDpdkVnfSetupEnvHelper(unittest.TestCase): ssh_helper = mock.MagicMock() scenario_helper = mock.MagicMock() - helper = ProxDpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper) + helper = prox_helpers.ProxDpdkVnfSetupEnvHelper( + vnfd_helper, ssh_helper, scenario_helper) helper.additional_files = {} helper.remote_prox_file_name = 'remote' vnfd_helper.interfaces = [ @@ -1254,7 +1296,8 @@ class TestProxDpdkVnfSetupEnvHelper(unittest.TestCase): ssh_helper = mock.MagicMock() scenario_helper = mock.MagicMock() - helper = ProxDpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper) + helper = prox_helpers.ProxDpdkVnfSetupEnvHelper( + vnfd_helper, ssh_helper, scenario_helper) expected = 'a/b' result = helper.put_string_to_file('my long string', 'a/b') @@ -1266,7 +1309,8 @@ class TestProxDpdkVnfSetupEnvHelper(unittest.TestCase): ssh_helper = mock.MagicMock() scenario_helper = mock.MagicMock() - helper = ProxDpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper) + helper = prox_helpers.ProxDpdkVnfSetupEnvHelper( + vnfd_helper, ssh_helper, scenario_helper) expected = '/tmp/c' result = helper.copy_to_target('a/b', 'c') self.assertEqual(result, expected) @@ -1277,7 +1321,8 @@ class TestProxDpdkVnfSetupEnvHelper(unittest.TestCase): ssh_helper = mock.MagicMock() scenario_helper = mock.MagicMock() - helper = ProxDpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper) + helper = prox_helpers.ProxDpdkVnfSetupEnvHelper( + vnfd_helper, ssh_helper, scenario_helper) helper.write_prox_config = mock.MagicMock(return_value='a long string') expected = '/tmp/a' result = helper.upload_prox_config('a', {}) @@ -1396,7 +1441,8 @@ class TestProxResourceHelper(unittest.TestCase): 'nor here', 'and still not', ] - result = ProxResourceHelper.find_pci('target', input_str_list) + result = prox_helpers.ProxResourceHelper.find_pci('target', + input_str_list) self.assertFalse(result) input_str_list = [ @@ -1405,13 +1451,14 @@ class TestProxResourceHelper(unittest.TestCase): 'this is a target', 'did we miss it', ] - result = ProxResourceHelper.find_pci('target', input_str_list) + result = prox_helpers.ProxResourceHelper.find_pci('target', + input_str_list) self.assertTrue(result) @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.RETRY_INTERVAL', 0) @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.ProxSocketHelper') def test_sut(self, *args): - helper = ProxResourceHelper(mock.MagicMock()) + helper = prox_helpers.ProxResourceHelper(mock.MagicMock()) self.assertIsNone(helper.client) result = helper.sut self.assertIsNotNone(result) @@ -1422,7 +1469,7 @@ class TestProxResourceHelper(unittest.TestCase): setup_helper = mock.MagicMock() setup_helper.find_in_section.return_value = expected = 'prox type' - helper = ProxResourceHelper(setup_helper) + helper = prox_helpers.ProxResourceHelper(setup_helper) self.assertIsNone(helper._test_type) self.assertEqual(helper.test_type, expected) @@ -1430,7 +1477,7 @@ class TestProxResourceHelper(unittest.TestCase): self.assertEqual(helper.test_type, expected) def test_collect_collectd_kpi(self): - helper = ProxResourceHelper(mock.MagicMock()) + helper = prox_helpers.ProxResourceHelper(mock.MagicMock()) helper.resource = resource = mock.MagicMock() resource.check_if_system_agent_running.return_value = 0, '1234' @@ -1442,7 +1489,7 @@ class TestProxResourceHelper(unittest.TestCase): self.assertDictEqual(result, expected) def test_collect_kpi(self): - helper = ProxResourceHelper(mock.MagicMock()) + helper = prox_helpers.ProxResourceHelper(mock.MagicMock()) helper._queue = queue = mock.MagicMock() helper._result = {'z': 123} helper.resource = resource = mock.MagicMock() @@ -1467,7 +1514,7 @@ class TestProxResourceHelper(unittest.TestCase): setup_helper = mock.MagicMock() setup_helper.vnfd_helper.interfaces = [] - helper = ProxResourceHelper(setup_helper) + helper = prox_helpers.ProxResourceHelper(setup_helper) result = helper._connect() self.assertIs(result, client) @@ -1479,47 +1526,48 @@ class TestProxResourceHelper(unittest.TestCase): def test_run_traffic(self): setup_helper = mock.MagicMock() - helper = ProxResourceHelper(setup_helper) + helper = prox_helpers.ProxResourceHelper(setup_helper) traffic_profile = mock.MagicMock(**{"done": True}) helper.run_traffic(traffic_profile) self.assertEqual(helper._terminated.value, 1) def test__run_traffic_once(self): setup_helper = mock.MagicMock() - helper = ProxResourceHelper(setup_helper) + helper = prox_helpers.ProxResourceHelper(setup_helper) traffic_profile = mock.MagicMock(**{"done": True}) helper._run_traffic_once(traffic_profile) self.assertEqual(helper._terminated.value, 1) def test_start_collect(self): setup_helper = mock.MagicMock() - helper = ProxResourceHelper(setup_helper) + helper = prox_helpers.ProxResourceHelper(setup_helper) helper.resource = resource = mock.MagicMock() self.assertIsNone(helper.start_collect()) resource.start.assert_called_once() def test_terminate(self): setup_helper = mock.MagicMock() - helper = ProxResourceHelper(setup_helper) + helper = prox_helpers.ProxResourceHelper(setup_helper) with self.assertRaises(NotImplementedError): helper.terminate() def test_up_post(self): setup_helper = mock.MagicMock() - helper = ProxResourceHelper(setup_helper) + helper = prox_helpers.ProxResourceHelper(setup_helper) helper.client = expected = mock.MagicMock() result = helper.up_post() self.assertEqual(result, expected) def test_execute(self): setup_helper = mock.MagicMock() - helper = ProxResourceHelper(setup_helper) + helper = prox_helpers.ProxResourceHelper(setup_helper) helper.client = mock.MagicMock() expected = helper.client.my_command() result = helper.execute('my_command') self.assertEqual(result, expected) + # TODO(elfoley): Make this a separate test: test_execute_no_client helper.client = object() result = helper.execute('my_command') @@ -1534,34 +1582,35 @@ class TestProxDataHelper(unittest.TestCase): vnfd_helper.port_pairs.all_ports = list(range(4)) sut = mock.MagicMock() - sut.port_stats.return_value = list(range(10)) + sut.multi_port_stats.return_value = [[0, 1, 2, 3, 4, 5], [1, 1, 2, 3, 4, 5], + [2, 1, 2, 3, 4, 5], [3, 1, 2, 3, 4, 5]] - data_helper = ProxDataHelper( + data_helper = prox_helpers.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) - self.assertEqual(data_helper.pps, 6.25e6) + self.assertEqual(data_helper.rx_total, 4) + self.assertEqual(data_helper.tx_total, 8) + self.assertEqual(data_helper.requested_pps, 6.25e6) def test_samples(self): vnfd_helper = mock.MagicMock() - vnfd_helper.port_pairs.all_ports = list(range(4)) - vnfd_helper.ports_iter.return_value = [('xe1', 3), ('xe2', 7)] + vnfd_helper.ports_iter.return_value = [('xe0', 0), ('xe1', 1)] sut = mock.MagicMock() - sut.port_stats.return_value = list(range(10)) + sut.multi_port_stats.return_value = [[0, 1, 2, 3, 4, 5], [1, 11, 12, 3, 4, 5]] - data_helper = ProxDataHelper(vnfd_helper, sut, None, None, None, None) + data_helper = prox_helpers.ProxDataHelper( + vnfd_helper, sut, None, None, None, None) expected = { - 'xe1': { - 'in_packets': 6, - 'out_packets': 7, + 'xe0': { + 'in_packets': 1, + 'out_packets': 2, }, - 'xe2': { - 'in_packets': 6, - 'out_packets': 7, + 'xe1': { + 'in_packets': 11, + 'out_packets': 12, }, } result = data_helper.samples @@ -1575,17 +1624,19 @@ class TestProxDataHelper(unittest.TestCase): sut = mock.MagicMock() sut.port_stats.return_value = list(range(10)) - data_helper = ProxDataHelper(vnfd_helper, sut, None, None, + data_helper = prox_helpers.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.measured_stats = { + 'delta': prox_helpers.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) + expected = prox_helpers.ProxTestDataTuple( + 5.4, 9.8, 6.1, 6.2, 6.3, 7, 12, 32, 4.5) with data_helper: pass @@ -1598,7 +1649,8 @@ class TestProxDataHelper(unittest.TestCase): def test___enter___negative(self): vnfd_helper = mock.MagicMock() - data_helper = ProxDataHelper(vnfd_helper, None, None, None, None, None) + data_helper = prox_helpers.ProxDataHelper( + vnfd_helper, None, None, None, None, None) vnfd_helper.port_pairs.all_ports = [] with self.assertRaises(AssertionError): @@ -1617,17 +1669,18 @@ class TestProxDataHelper(unittest.TestCase): start = (3, 4, 1, 2) end = (9, 7, 6, 8) - sut = ProxSocketHelper(mock.MagicMock()) + sut = prox_helpers.ProxSocketHelper(mock.MagicMock()) sut.get_all_tot_stats = mock.MagicMock(side_effect=[start, end]) - data_helper = ProxDataHelper(vnfd_helper, sut, None, None, 5.4, None) + data_helper = prox_helpers.ProxDataHelper( + vnfd_helper, sut, None, None, 5.4, None) self.assertIsNone(data_helper.measured_stats) expected = { 'start_tot': start, 'end_tot': end, - 'delta': TotStatsTuple(6, 3, 5, 6), + 'delta': prox_helpers.TotStatsTuple(6, 3, 5, 6), } with data_helper.measure_tot_stats(): pass @@ -1641,7 +1694,8 @@ class TestProxDataHelper(unittest.TestCase): sut = mock.MagicMock() sut.hz.return_value = '54.6' - data_helper = ProxDataHelper(vnfd_helper, sut, None, None, None, None) + data_helper = prox_helpers.ProxDataHelper( + vnfd_helper, sut, None, None, None, None) self.assertIsNone(data_helper.tsc_hz) @@ -1660,12 +1714,13 @@ class TestProxProfileHelper(unittest.TestCase): mock_type2.__prox_profile_type__ = 'my_type' mock_utils.itersubclasses.return_value = [mock_type1, mock_type2] - self.assertEqual(ProxProfileHelper.get_cls('my_type'), mock_type2) + self.assertEqual(prox_helpers.ProxProfileHelper.get_cls('my_type'), + mock_type2) @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.utils') def test_get_cls_default(self, mock_utils): mock_utils.itersubclasses.return_value = [] - ProxProfileHelper.get_cls('my_type') + prox_helpers.ProxProfileHelper.get_cls('my_type') @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.SocketTopology') def test_cpu_topology(self, mock_socket_topology): @@ -1674,18 +1729,19 @@ class TestProxProfileHelper(unittest.TestCase): resource_helper = mock.MagicMock() resource_helper.setup_helper.ssh_helper.execute.return_value = 0, 'output', '' - helper = ProxProfileHelper(resource_helper) + helper = prox_helpers.ProxProfileHelper(resource_helper) self.assertIsNone(helper._cpu_topology) result = helper.cpu_topology self.assertEqual(result, 432) self.assertIs(result, helper._cpu_topology) self.assertIs(result, helper.cpu_topology) + # TODO(elfoley): Split this test; there are two sets of inputs/outputs def test_test_cores(self): resource_helper = mock.MagicMock() resource_helper.setup_helper.prox_config_data = [] - helper = ProxProfileHelper(resource_helper) + helper = prox_helpers.ProxProfileHelper(resource_helper) helper._cpu_topology = [] expected = [] @@ -1713,7 +1769,7 @@ class TestProxProfileHelper(unittest.TestCase): ]), ] - helper = ProxProfileHelper(resource_helper) + helper = prox_helpers.ProxProfileHelper(resource_helper) helper._cpu_topology = { 1: { 3: { @@ -1738,11 +1794,12 @@ class TestProxProfileHelper(unittest.TestCase): self.assertIs(result, helper._test_cores) self.assertIs(result, helper.test_cores) + # TODO(elfoley): Split this test; there are two sets of inputs/outputs def test_latency_cores(self): resource_helper = mock.MagicMock() resource_helper.setup_helper.prox_config_data = [] - helper = ProxProfileHelper(resource_helper) + helper = prox_helpers.ProxProfileHelper(resource_helper) helper._cpu_topology = [] expected = [] @@ -1770,7 +1827,7 @@ class TestProxProfileHelper(unittest.TestCase): ]), ] - helper = ProxProfileHelper(resource_helper) + helper = prox_helpers.ProxProfileHelper(resource_helper) helper._cpu_topology = { 1: { 3: { @@ -1796,7 +1853,7 @@ class TestProxProfileHelper(unittest.TestCase): self.assertIs(result, helper.latency_cores) def test_all_rx_cores(self): - helper = ProxBngProfileHelper(mock.MagicMock()) + helper = prox_helpers.ProxBngProfileHelper(mock.MagicMock()) helper._latency_cores = expected = [3, 4, 6] helper._test_cores = [5, 2, 1] @@ -1826,7 +1883,7 @@ class TestProxProfileHelper(unittest.TestCase): ]), ] - helper = ProxProfileHelper(resource_helper) + helper = prox_helpers.ProxProfileHelper(resource_helper) helper._cpu_topology = { 0: { 1: { @@ -1852,7 +1909,7 @@ class TestProxProfileHelper(unittest.TestCase): resource_helper = mock.MagicMock() resource_helper.setup_helper.vnfd_helper.interfaces = [] - helper = ProxProfileHelper(resource_helper) + helper = prox_helpers.ProxProfileHelper(resource_helper) helper._latency_cores = [] expected = [] @@ -1871,7 +1928,7 @@ class TestProxProfileHelper(unittest.TestCase): setup_helper = mock.MagicMock() setup_helper.vnfd_helper.interfaces = [] - helper = ProxProfileHelper(setup_helper) + helper = prox_helpers.ProxProfileHelper(setup_helper) helper._cpu_topology = { 0: { 1: { @@ -1936,7 +1993,7 @@ class TestProxProfileHelper(unittest.TestCase): resource_helper.vnfd_helper.port_pairs.all_ports = list(range(2)) resource_helper.sut.port_stats.return_value = list(range(10)) - helper = ProxProfileHelper(resource_helper) + helper = prox_helpers.ProxProfileHelper(resource_helper) helper.run_test(120, 5, 6.5, constants.NIC_GBPS_DEFAULT * constants.ONE_GIGABIT_IN_BITS) @@ -1969,7 +2026,7 @@ class TestProxMplsProfileHelper(unittest.TestCase): ]), ] - helper = ProxMplsProfileHelper(resource_helper) + helper = prox_helpers.ProxMplsProfileHelper(resource_helper) helper._cpu_topology = { 0: { 1: { @@ -1996,7 +2053,7 @@ class TestProxMplsProfileHelper(unittest.TestCase): def test_traffic_context(self): setup_helper = mock.MagicMock() - helper = ProxMplsProfileHelper(setup_helper) + helper = prox_helpers.ProxMplsProfileHelper(setup_helper) with helper.traffic_context(120, 5.4): pass @@ -2039,7 +2096,7 @@ class TestProxBngProfileHelper(unittest.TestCase): ]), ] - helper = ProxBngProfileHelper(resource_helper) + helper = prox_helpers.ProxBngProfileHelper(resource_helper) helper._cpu_topology = { 0: { 1: { @@ -2083,7 +2140,7 @@ class TestProxBngProfileHelper(unittest.TestCase): resource_helper.vnfd_helper.port_pairs.all_ports = list(range(2)) resource_helper.sut.port_stats.return_value = list(range(10)) - helper = ProxBngProfileHelper(resource_helper) + helper = prox_helpers.ProxBngProfileHelper(resource_helper) helper.run_test(120, 5, 6.5, constants.NIC_GBPS_DEFAULT * constants.ONE_GIGABIT_IN_BITS) @@ -2120,7 +2177,7 @@ class TestProxVpeProfileHelper(unittest.TestCase): ]), ] - helper = ProxVpeProfileHelper(resource_helper) + helper = prox_helpers.ProxVpeProfileHelper(resource_helper) helper._cpu_topology = { 0: { 1: { @@ -2167,7 +2224,7 @@ class TestProxVpeProfileHelper(unittest.TestCase): ]), ] - helper = ProxVpeProfileHelper(resource_helper) + helper = prox_helpers.ProxVpeProfileHelper(resource_helper) helper._port_list = { 0: { 1: { @@ -2201,7 +2258,7 @@ class TestProxVpeProfileHelper(unittest.TestCase): resource_helper.vnfd_helper.port_pairs.all_ports = list(range(2)) resource_helper.sut.port_stats.return_value = list(range(10)) - helper = ProxVpeProfileHelper(resource_helper) + helper = prox_helpers.ProxVpeProfileHelper(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 @@ -2234,7 +2291,7 @@ class TestProxlwAFTRProfileHelper(unittest.TestCase): ]), ] - helper = ProxlwAFTRProfileHelper(resource_helper) + helper = prox_helpers.ProxlwAFTRProfileHelper(resource_helper) helper._cpu_topology = { 0: { 1: { @@ -2281,7 +2338,7 @@ class TestProxlwAFTRProfileHelper(unittest.TestCase): ]), ] - helper = ProxlwAFTRProfileHelper(resource_helper) + helper = prox_helpers.ProxlwAFTRProfileHelper(resource_helper) helper._port_list = { 0: { 1: { @@ -2315,7 +2372,7 @@ class TestProxlwAFTRProfileHelper(unittest.TestCase): resource_helper.vnfd_helper.port_pairs.all_ports = list(range(2)) resource_helper.sut.port_stats.return_value = list(range(10)) - helper = ProxlwAFTRProfileHelper(resource_helper) + helper = prox_helpers.ProxlwAFTRProfileHelper(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 diff --git a/tests/unit/network_services/vnf_generic/vnf/test_prox_vnf.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_prox_vnf.py index 159b1f718..f144e8c42 100644 --- a/tests/unit/network_services/vnf_generic/vnf/test_prox_vnf.py +++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_prox_vnf.py @@ -19,7 +19,8 @@ import unittest import mock from copy import deepcopy -from tests.unit import STL_MOCKS +from yardstick.tests import STL_MOCKS +from yardstick.benchmark.contexts import base as ctx_base SSH_HELPER = 'yardstick.network_services.vnf_generic.vnf.sample_vnf.VnfSshHelper' @@ -29,8 +30,8 @@ stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) stl_patch.start() if stl_patch: - from yardstick.network_services.vnf_generic.vnf.prox_vnf import ProxApproxVnf - from tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh + from yardstick.network_services.vnf_generic.vnf import prox_vnf + from yardstick.tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh NAME = "vnf__1" @@ -187,7 +188,7 @@ class TestProxApproxVnf(unittest.TestCase): 'interfaces': { 'xe0': { 'local_iface_name': 'ens513f0', - 'vld_id': ProxApproxVnf.DOWNLINK, + 'vld_id': prox_vnf.ProxApproxVnf.DOWNLINK, 'netmask': '255.255.255.0', 'local_ip': '152.16.40.20', 'dst_mac': '00:00:00:00:00:01', @@ -221,7 +222,7 @@ class TestProxApproxVnf(unittest.TestCase): 'interfaces': { 'xe0': { 'local_iface_name': 'ens785f0', - 'vld_id': ProxApproxVnf.UPLINK, + 'vld_id': prox_vnf.ProxApproxVnf.UPLINK, 'netmask': '255.255.255.0', 'local_ip': '152.16.100.20', 'dst_mac': '00:00:00:00:00:02', @@ -252,7 +253,7 @@ class TestProxApproxVnf(unittest.TestCase): 'interfaces': { 'xe0': { 'local_iface_name': 'ens786f0', - 'vld_id': ProxApproxVnf.UPLINK, + 'vld_id': prox_vnf.ProxApproxVnf.UPLINK, 'netmask': '255.255.255.0', 'local_ip': '152.16.100.19', 'dst_mac': '00:00:00:00:00:04', @@ -264,7 +265,7 @@ class TestProxApproxVnf(unittest.TestCase): }, 'xe1': { 'local_iface_name': 'ens786f1', - 'vld_id': ProxApproxVnf.DOWNLINK, + 'vld_id': prox_vnf.ProxApproxVnf.DOWNLINK, 'netmask': '255.255.255.0', 'local_ip': '152.16.40.19', 'dst_mac': '00:00:00:00:00:03', @@ -316,16 +317,21 @@ class TestProxApproxVnf(unittest.TestCase): @mock.patch(SSH_HELPER) def test___init__(self, ssh, *args): mock_ssh(ssh) - prox_approx_vnf = ProxApproxVnf(NAME, self.VNFD0) + prox_approx_vnf = prox_vnf.ProxApproxVnf(NAME, self.VNFD0, 'task_id') self.assertIsNone(prox_approx_vnf._vnf_process) + @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', return_value='mock_node') @mock.patch(SSH_HELPER) def test_collect_kpi_no_client(self, ssh, *args): mock_ssh(ssh) - prox_approx_vnf = ProxApproxVnf(NAME, self.VNFD0) + prox_approx_vnf = prox_vnf.ProxApproxVnf(NAME, self.VNFD0, 'task_id') + prox_approx_vnf.scenario_helper.scenario_cfg = { + 'nodes': {prox_approx_vnf.name: "mock"} + } prox_approx_vnf.resource_helper = None expected = { + 'physical_node': 'mock_node', 'packets_in': 0, 'packets_dropped': 0, 'packets_fwd': 0, @@ -334,21 +340,27 @@ class TestProxApproxVnf(unittest.TestCase): result = prox_approx_vnf.collect_kpi() self.assertEqual(result, expected) + @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', return_value='mock_node') @mock.patch(SSH_HELPER) def test_collect_kpi(self, ssh, *args): mock_ssh(ssh) resource_helper = mock.MagicMock() - resource_helper.execute.return_value = list(range(12)) + resource_helper.execute.return_value = [[0, 1, 2, 3, 4, 5], [1, 1, 2, 3, 4, 5], + [2, 1, 2, 3, 4, 5], [3, 1, 2, 3, 4, 5]] resource_helper.collect_collectd_kpi.return_value = {'core': {'result': 234}} - prox_approx_vnf = ProxApproxVnf(NAME, self.VNFD0) + prox_approx_vnf = prox_vnf.ProxApproxVnf(NAME, self.VNFD0, 'task_id') + prox_approx_vnf.scenario_helper.scenario_cfg = { + 'nodes': {prox_approx_vnf.name: "mock"} + } prox_approx_vnf.resource_helper = resource_helper expected = { - 'packets_in': 6, - 'packets_dropped': 1, - 'packets_fwd': 7, + 'physical_node': 'mock_node', + 'packets_in': 4, + 'packets_dropped': 4, + 'packets_fwd': 8, 'collect_stats': {'core': {'result': 234}}, } result = prox_approx_vnf.collect_kpi() @@ -358,13 +370,17 @@ class TestProxApproxVnf(unittest.TestCase): self.assertNotEqual(result['packets_fwd'], 0) self.assertNotEqual(result['packets_fwd'], 0) + @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', return_value='mock_node') @mock.patch(SSH_HELPER) def test_collect_kpi_error(self, ssh, *args): mock_ssh(ssh) resource_helper = mock.MagicMock() - - prox_approx_vnf = ProxApproxVnf(NAME, deepcopy(self.VNFD0)) + prox_approx_vnf = prox_vnf.ProxApproxVnf(NAME, deepcopy(self.VNFD0), + 'task_id') + prox_approx_vnf.scenario_helper.scenario_cfg = { + 'nodes': {prox_approx_vnf.name: "mock"} + } prox_approx_vnf.resource_helper = resource_helper prox_approx_vnf.vnfd_helper['vdu'][0]['external-interface'] = [] prox_approx_vnf.vnfd_helper.port_pairs.interfaces = [] @@ -384,7 +400,7 @@ class TestProxApproxVnf(unittest.TestCase): def test_run_prox(self, ssh, *_): mock_ssh(ssh) - prox_approx_vnf = ProxApproxVnf(NAME, self.VNFD0) + prox_approx_vnf = prox_vnf.ProxApproxVnf(NAME, self.VNFD0, 'task_id') prox_approx_vnf.scenario_helper.scenario_cfg = self.SCENARIO_CFG prox_approx_vnf.ssh_helper.join_bin_path.return_value = '/tool_path12/tool_file34' prox_approx_vnf.setup_helper.remote_path = 'configs/file56.cfg' @@ -398,7 +414,7 @@ class TestProxApproxVnf(unittest.TestCase): @mock.patch(SSH_HELPER) def bad_test_instantiate(self, *args): - prox_approx_vnf = ProxApproxVnf(NAME, self.VNFD0) + prox_approx_vnf = prox_vnf.ProxApproxVnf(NAME, self.VNFD0, 'task_id') prox_approx_vnf.scenario_helper = mock.MagicMock() prox_approx_vnf.setup_helper = mock.MagicMock() # we can't mock super @@ -408,7 +424,7 @@ class TestProxApproxVnf(unittest.TestCase): @mock.patch(SSH_HELPER) def test_wait_for_instantiate_panic(self, ssh, *args): mock_ssh(ssh, exec_result=(1, "", "")) - prox_approx_vnf = ProxApproxVnf(NAME, self.VNFD0) + prox_approx_vnf = prox_vnf.ProxApproxVnf(NAME, self.VNFD0, 'task_id') prox_approx_vnf._vnf_process = mock.MagicMock(**{"is_alive.return_value": True}) prox_approx_vnf._run_prox = mock.Mock(return_value=0) prox_approx_vnf.WAIT_TIME = 0 @@ -420,7 +436,7 @@ class TestProxApproxVnf(unittest.TestCase): @mock.patch(SSH_HELPER) def test_terminate(self, ssh, *args): mock_ssh(ssh) - prox_approx_vnf = ProxApproxVnf(NAME, self.VNFD0) + prox_approx_vnf = prox_vnf.ProxApproxVnf(NAME, self.VNFD0, 'task_id') prox_approx_vnf._vnf_process = mock.MagicMock() prox_approx_vnf._vnf_process.terminate = mock.Mock() prox_approx_vnf.ssh_helper = mock.MagicMock() @@ -432,16 +448,16 @@ class TestProxApproxVnf(unittest.TestCase): @mock.patch(SSH_HELPER) def test__vnf_up_post(self, ssh, *args): mock_ssh(ssh) - prox_approx_vnf = ProxApproxVnf(NAME, self.VNFD0) + prox_approx_vnf = prox_vnf.ProxApproxVnf(NAME, self.VNFD0, 'task_id') prox_approx_vnf.resource_helper = resource_helper = mock.Mock() prox_approx_vnf._vnf_up_post() - self.assertEqual(resource_helper.up_post.call_count, 1) + resource_helper.up_post.assert_called_once() @mock.patch(SSH_HELPER) def test_vnf_execute_oserror(self, ssh, *args): mock_ssh(ssh) - prox_approx_vnf = ProxApproxVnf(NAME, self.VNFD0) + prox_approx_vnf = prox_vnf.ProxApproxVnf(NAME, self.VNFD0, 'task_id') prox_approx_vnf.resource_helper = resource_helper = mock.Mock() resource_helper.execute.side_effect = OSError(errno.EPIPE, "") diff --git a/tests/unit/network_services/vnf_generic/vnf/test_router_vnf.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_router_vnf.py index c6292f258..ad74145b4 100644 --- a/tests/unit/network_services/vnf_generic/vnf/test_router_vnf.py +++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_router_vnf.py @@ -11,23 +11,13 @@ # 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. -# - -from __future__ import absolute_import import unittest import mock -from tests.unit import STL_MOCKS -from tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh - - -STLClient = mock.MagicMock() -stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) -stl_patch.start() - -if stl_patch: - from yardstick.network_services.vnf_generic.vnf.router_vnf import RouterVNF +from yardstick.tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh +from yardstick.benchmark.contexts import base as ctx_base +from yardstick.network_services.vnf_generic.vnf.router_vnf import RouterVNF TEST_FILE_YAML = 'nsb_test_case.yaml' @@ -209,22 +199,32 @@ class TestRouterVNF(unittest.TestCase): def test___init__(self): vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - router_vnf = RouterVNF(name, vnfd) + router_vnf = RouterVNF(name, vnfd, 'task_id') self.assertIsNone(router_vnf._vnf_process) def test_get_stats(self): stats = RouterVNF.get_stats(self.IP_SHOW_STATS_OUTPUT) self.assertDictEqual(stats, self.STATS) + @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', return_value='mock_node') @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.time") @mock.patch(SSH_HELPER) - def test_collect_kpi(self, ssh, _): + def test_collect_kpi(self, ssh, *args): m = mock_ssh(ssh) vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - router_vnf = RouterVNF(name, vnfd) + router_vnf = RouterVNF(name, vnfd, 'task_id') + router_vnf.scenario_helper.scenario_cfg = { + 'nodes': {router_vnf.name: "mock"} + } router_vnf.ssh_helper = m - result = {'packets_dropped': 0, 'packets_fwd': 0, 'packets_in': 0, 'link_stats': {}} + result = { + 'physical_node': 'mock_node', + 'packets_dropped': 0, + 'packets_fwd': 0, + 'packets_in': 0, + 'link_stats': {} + } self.assertEqual(result, router_vnf.collect_kpi()) @mock.patch(SSH_HELPER) @@ -232,18 +232,18 @@ class TestRouterVNF(unittest.TestCase): mock_ssh(ssh) vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - router_vnf = RouterVNF(name, vnfd) + router_vnf = RouterVNF(name, vnfd, 'task_id') router_vnf.scenario_helper.scenario_cfg = self.scenario_cfg router_vnf._run() router_vnf.ssh_helper.drop_connection.assert_called_once() - @mock.patch("yardstick.network_services.vnf_generic.vnf.router_vnf.Context") + @mock.patch.object(ctx_base, 'Context') @mock.patch(SSH_HELPER) - def test_instantiate(self, ssh, _): + def test_instantiate(self, ssh, *args): mock_ssh(ssh) vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - router_vnf = RouterVNF(name, vnfd) + router_vnf = RouterVNF(name, vnfd, 'task_id') router_vnf.WAIT_TIME = 0 router_vnf.INTERFACE_WAIT = 0 self.scenario_cfg.update({"nodes": {"vnf__1": ""}}) @@ -256,7 +256,7 @@ class TestRouterVNF(unittest.TestCase): mock_ssh(ssh) vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - router_vnf = RouterVNF(name, vnfd) + router_vnf = RouterVNF(name, vnfd, 'task_id') router_vnf._vnf_process = mock.MagicMock() router_vnf._vnf_process.terminate = mock.Mock() self.assertIsNone(router_vnf.terminate()) diff --git a/tests/unit/network_services/vnf_generic/vnf/test_sample_vnf.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_sample_vnf.py index 38a043d00..c35d2db35 100644 --- a/tests/unit/network_services/vnf_generic/vnf/test_sample_vnf.py +++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_sample_vnf.py @@ -11,7 +11,6 @@ # 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. -# from copy import deepcopy @@ -19,37 +18,29 @@ import unittest import mock import six -from tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh -from tests.unit import STL_MOCKS -from yardstick.benchmark.contexts.base import Context from yardstick.common import exceptions as y_exceptions from yardstick.common import utils from yardstick.network_services.nfvi.resource import ResourceProfile from yardstick.network_services.vnf_generic.vnf.base import VnfdHelper - - -class MockError(BaseException): +from yardstick.network_services.vnf_generic.vnf import sample_vnf +from yardstick.network_services.vnf_generic.vnf.vnf_ssh_helper import VnfSshHelper +from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNFDeployHelper +from yardstick.network_services.vnf_generic.vnf.sample_vnf import ScenarioHelper +from yardstick.network_services.vnf_generic.vnf.sample_vnf import ResourceHelper +from yardstick.network_services.vnf_generic.vnf.sample_vnf import ClientResourceHelper +from yardstick.network_services.vnf_generic.vnf.sample_vnf import Rfc2544ResourceHelper +from yardstick.network_services.vnf_generic.vnf.sample_vnf import SetupEnvHelper +from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNF +from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNFTrafficGen +from yardstick.network_services.vnf_generic.vnf.sample_vnf import DpdkVnfSetupEnvHelper +from yardstick.tests.unit.network_services.vnf_generic.vnf import test_base +from yardstick.benchmark.contexts import base as ctx_base + + +class MockError(Exception): pass -STLClient = mock.MagicMock() -stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) -stl_patch.start() - -if stl_patch: - from yardstick.network_services.vnf_generic.vnf import sample_vnf - from yardstick.network_services.vnf_generic.vnf.vnf_ssh_helper import VnfSshHelper - from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNFDeployHelper - from yardstick.network_services.vnf_generic.vnf.sample_vnf import ScenarioHelper - from yardstick.network_services.vnf_generic.vnf.sample_vnf import ResourceHelper - from yardstick.network_services.vnf_generic.vnf.sample_vnf import ClientResourceHelper - from yardstick.network_services.vnf_generic.vnf.sample_vnf import Rfc2544ResourceHelper - from yardstick.network_services.vnf_generic.vnf.sample_vnf import SetupEnvHelper - from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNF - from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNFTrafficGen - from yardstick.network_services.vnf_generic.vnf.sample_vnf import DpdkVnfSetupEnvHelper - - class TestVnfSshHelper(unittest.TestCase): VNFD_0 = { @@ -192,12 +183,12 @@ class TestVnfSshHelper(unittest.TestCase): self.assertFalse(ssh_helper.is_connected) cfg_file = ssh_helper.upload_config_file('my/prefix', 'my content') self.assertTrue(ssh_helper.is_connected) - self.assertEqual(mock_paramiko.SSHClient.call_count, 1) + mock_paramiko.SSHClient.assert_called_once() self.assertTrue(cfg_file.startswith('/tmp')) cfg_file = ssh_helper.upload_config_file('/my/prefix', 'my content') self.assertTrue(ssh_helper.is_connected) - self.assertEqual(mock_paramiko.SSHClient.call_count, 1) + mock_paramiko.SSHClient.assert_called_once() self.assertEqual(cfg_file, '/my/prefix') def test_join_bin_path(self): @@ -234,17 +225,17 @@ class TestVnfSshHelper(unittest.TestCase): self.assertFalse(ssh_helper.is_connected) ssh_helper.provision_tool() self.assertTrue(ssh_helper.is_connected) - self.assertEqual(mock_paramiko.SSHClient.call_count, 1) - self.assertEqual(mock_provision_tool.call_count, 1) + mock_paramiko.SSHClient.assert_called_once() + mock_provision_tool.assert_called_once() ssh_helper.provision_tool(tool_file='my_tool.sh') self.assertTrue(ssh_helper.is_connected) - self.assertEqual(mock_paramiko.SSHClient.call_count, 1) + mock_paramiko.SSHClient.assert_called_once() self.assertEqual(mock_provision_tool.call_count, 2) ssh_helper.provision_tool('tool_path', 'my_tool.sh') self.assertTrue(ssh_helper.is_connected) - self.assertEqual(mock_paramiko.SSHClient.call_count, 1) + mock_paramiko.SSHClient.assert_called_once() self.assertEqual(mock_provision_tool.call_count, 3) @@ -572,6 +563,7 @@ class TestDpdkVnfSetupEnvHelper(unittest.TestCase): ssh_helper = mock.Mock() scenario_helper = mock.Mock() scenario_helper.vnf_cfg = {} + scenario_helper.options = {} scenario_helper.all_options = {} dpdk_setup_helper = DpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper) @@ -579,10 +571,11 @@ class TestDpdkVnfSetupEnvHelper(unittest.TestCase): result = dpdk_setup_helper.build_config() self.assertEqual(result, expected) self.assertGreaterEqual(ssh_helper.upload_config_file.call_count, 2) - self.assertGreaterEqual(mock_find.call_count, 1) - self.assertGreaterEqual(mock_multi_port_config.generate_config.call_count, 1) - self.assertGreaterEqual(mock_multi_port_config.generate_script.call_count, 1) + mock_find.assert_called() + mock_multi_port_config.generate_config.assert_called() + mock_multi_port_config.generate_script.assert_called() + scenario_helper.options = {'rules': 'fake_file'} scenario_helper.vnf_cfg = {'file': 'fake_file'} dpdk_setup_helper = DpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper) mock_open_rf.side_effect = mock.mock_open(read_data='fake_data') @@ -590,12 +583,12 @@ class TestDpdkVnfSetupEnvHelper(unittest.TestCase): result = dpdk_setup_helper.build_config() - mock_open_rf.assert_called_once() + mock_open_rf.assert_called() self.assertEqual(result, expected) self.assertGreaterEqual(ssh_helper.upload_config_file.call_count, 2) - self.assertGreaterEqual(mock_find.call_count, 1) - self.assertGreaterEqual(mock_multi_port_config.generate_config.call_count, 1) - self.assertGreaterEqual(mock_multi_port_config.generate_script.call_count, 1) + mock_find.assert_called() + mock_multi_port_config.generate_config.assert_called() + mock_multi_port_config.generate_script.assert_called() def test__build_pipeline_kwargs(self): vnfd_helper = VnfdHelper(self.VNFD_0) @@ -607,12 +600,15 @@ class TestDpdkVnfSetupEnvHelper(unittest.TestCase): dpdk_setup_helper.CFG_SCRIPT = 'script' dpdk_setup_helper.pipeline_kwargs = {} dpdk_setup_helper.all_ports = [0, 1, 2] + dpdk_setup_helper.scenario_helper.vnf_cfg = {'lb_config': 'HW', + 'worker_threads': 1} expected = { 'cfg_file': 'config', 'script': 'script', 'port_mask_hex': '0x3', 'tool_path': 'tool_path', + 'hwlb': ' --hwlb 1', } dpdk_setup_helper._build_pipeline_kwargs() self.assertDictEqual(dpdk_setup_helper.pipeline_kwargs, expected) @@ -998,203 +994,69 @@ class TestClientResourceHelper(unittest.TestCase): } @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.LOG') - @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.STLError', - new_callable=lambda: MockError) - def test_get_stats_not_connected(self, mock_state_error, *args): + @mock.patch.object(sample_vnf, 'STLError', new_callable=lambda: MockError) + def test_get_stats_not_connected(self, mock_stl_error, *args): vnfd_helper = VnfdHelper(self.VNFD_0) ssh_helper = mock.Mock() scenario_helper = mock.Mock() - dpdk_setup_helper = DpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper) + dpdk_setup_helper = DpdkVnfSetupEnvHelper( + vnfd_helper, ssh_helper, scenario_helper) client_resource_helper = ClientResourceHelper(dpdk_setup_helper) - client_resource_helper.client = mock.MagicMock() - client_resource_helper.client.get_stats.side_effect = mock_state_error + client_resource_helper.client = mock.Mock() + client_resource_helper.client.get_stats.side_effect = mock_stl_error self.assertEqual(client_resource_helper.get_stats(), {}) - self.assertEqual(client_resource_helper.client.get_stats.call_count, 1) - - def test_generate_samples(self): - vnfd_helper = VnfdHelper(self.VNFD_0) - ssh_helper = mock.Mock() - scenario_helper = mock.Mock() - dpdk_setup_helper = DpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper) - client_resource_helper = ClientResourceHelper(dpdk_setup_helper) - client_resource_helper.client = mock.MagicMock() - client_resource_helper.client.get_stats.return_value = { - 0: { - 'rx_pps': 5.5, - 'tx_pps': 4.9, - 'rx_bps': 234.78, - 'tx_bps': 243.11, - 'ipackets': 34251, - 'opackets': 52342, - }, - 1: { - 'tx_pps': 5.9, - 'rx_bps': 434.78, - 'opackets': 48791, - }, - } - - expected = { - 'xe0': { - "rx_throughput_fps": 5.5, - "tx_throughput_fps": 4.9, - "rx_throughput_mbps": 234.78, - "tx_throughput_mbps": 243.11, - "in_packets": 34251, - "out_packets": 52342, - }, - 'xe1': { - "rx_throughput_fps": 0.0, - "tx_throughput_fps": 5.9, - "rx_throughput_mbps": 434.78, - "tx_throughput_mbps": 0.0, - "in_packets": 0, - "out_packets": 48791, - }, - } - ports = vnfd_helper.port_nums(vnfd_helper.port_pairs.all_ports) - result = client_resource_helper.generate_samples(ports) - self.assertDictEqual(result, expected) - - def test_generate_samples_with_key(self): - vnfd_helper = VnfdHelper(self.VNFD_0) - ssh_helper = mock.Mock() - scenario_helper = mock.Mock() - dpdk_setup_helper = DpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper) - client_resource_helper = ClientResourceHelper(dpdk_setup_helper) - client_resource_helper.client = mock.MagicMock() - client_resource_helper.client.get_stats.return_value = { - 'key_name': 'key_value', - 0: { - 'rx_pps': 5.5, - 'tx_pps': 4.9, - 'rx_bps': 234.78, - 'tx_bps': 243.11, - 'ipackets': 34251, - 'opackets': 52342, - }, - 1: { - 'tx_pps': 5.9, - 'rx_bps': 434.78, - 'opackets': 48791, - }, - } - - expected = { - 'xe0': { - 'key_name': 'key_value', - "rx_throughput_fps": 5.5, - "tx_throughput_fps": 4.9, - "rx_throughput_mbps": 234.78, - "tx_throughput_mbps": 243.11, - "in_packets": 34251, - "out_packets": 52342, - }, - 'xe1': { - 'key_name': 'key_value', - "rx_throughput_fps": 0.0, - "tx_throughput_fps": 5.9, - "rx_throughput_mbps": 434.78, - "tx_throughput_mbps": 0.0, - "in_packets": 0, - "out_packets": 48791, - }, - } - ports = vnfd_helper.port_nums(vnfd_helper.port_pairs.all_ports) - result = client_resource_helper.generate_samples(ports, 'key_name') - self.assertDictEqual(result, expected) - - def test_generate_samples_with_key_and_default(self): - vnfd_helper = VnfdHelper(self.VNFD_0) - ssh_helper = mock.Mock() - scenario_helper = mock.Mock() - dpdk_setup_helper = DpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper) - client_resource_helper = ClientResourceHelper(dpdk_setup_helper) - client_resource_helper.client = mock.MagicMock() - client_resource_helper.client.get_stats.return_value = { - 0: { - 'rx_pps': 5.5, - 'tx_pps': 4.9, - 'rx_bps': 234.78, - 'tx_bps': 243.11, - 'ipackets': 34251, - 'opackets': 52342, - }, - 1: { - 'tx_pps': 5.9, - 'rx_bps': 434.78, - 'opackets': 48791, - }, - } - - expected = { - 'xe0': { - 'key_name': 'default', - "rx_throughput_fps": 5.5, - "tx_throughput_fps": 4.9, - "rx_throughput_mbps": 234.78, - "tx_throughput_mbps": 243.11, - "in_packets": 34251, - "out_packets": 52342, - }, - 'xe1': { - 'key_name': 'default', - "rx_throughput_fps": 0.0, - "tx_throughput_fps": 5.9, - "rx_throughput_mbps": 434.78, - "tx_throughput_mbps": 0.0, - "in_packets": 0, - "out_packets": 48791, - }, - } - ports = vnfd_helper.port_nums(vnfd_helper.port_pairs.all_ports) - result = client_resource_helper.generate_samples(ports, 'key_name', 'default') - self.assertDictEqual(result, expected) + client_resource_helper.client.get_stats.assert_called_once() def test_clear_stats(self): vnfd_helper = VnfdHelper(self.VNFD_0) ssh_helper = mock.Mock() scenario_helper = mock.Mock() - dpdk_setup_helper = DpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper) + dpdk_setup_helper = DpdkVnfSetupEnvHelper( + vnfd_helper, ssh_helper, scenario_helper) client_resource_helper = ClientResourceHelper(dpdk_setup_helper) client_resource_helper.client = mock.Mock() self.assertIsNone(client_resource_helper.clear_stats()) - self.assertEqual(client_resource_helper.client.clear_stats.call_count, 1) + self.assertEqual( + client_resource_helper.client.clear_stats.call_count, 1) def test_clear_stats_of_ports(self): vnfd_helper = VnfdHelper(self.VNFD_0) ssh_helper = mock.Mock() scenario_helper = mock.Mock() - dpdk_setup_helper = DpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper) + dpdk_setup_helper = DpdkVnfSetupEnvHelper( + vnfd_helper, ssh_helper, scenario_helper) client_resource_helper = ClientResourceHelper(dpdk_setup_helper) client_resource_helper.client = mock.Mock() self.assertIsNone(client_resource_helper.clear_stats([3, 4])) - self.assertEqual(client_resource_helper.client.clear_stats.call_count, 1) + self.assertEqual( + client_resource_helper.client.clear_stats.call_count, 1) def test_start(self): vnfd_helper = VnfdHelper(self.VNFD_0) ssh_helper = mock.Mock() scenario_helper = mock.Mock() - dpdk_setup_helper = DpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper) + dpdk_setup_helper = DpdkVnfSetupEnvHelper( + vnfd_helper, ssh_helper, scenario_helper) client_resource_helper = ClientResourceHelper(dpdk_setup_helper) client_resource_helper.client = mock.Mock() self.assertIsNone(client_resource_helper.start()) - self.assertEqual(client_resource_helper.client.start.call_count, 1) + client_resource_helper.client.start.assert_called_once() def test_start_ports(self): vnfd_helper = VnfdHelper(self.VNFD_0) ssh_helper = mock.Mock() scenario_helper = mock.Mock() - dpdk_setup_helper = DpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper) + dpdk_setup_helper = DpdkVnfSetupEnvHelper( + vnfd_helper, ssh_helper, scenario_helper) client_resource_helper = ClientResourceHelper(dpdk_setup_helper) client_resource_helper.client = mock.Mock() self.assertIsNone(client_resource_helper.start([3, 4])) - self.assertEqual(client_resource_helper.client.start.call_count, 1) + client_resource_helper.client.start.assert_called_once() def test_collect_kpi_with_queue(self): vnfd_helper = VnfdHelper(self.VNFD_0) @@ -1216,20 +1078,69 @@ class TestClientResourceHelper(unittest.TestCase): self.assertDictEqual(result, expected) @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.time') - @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.LOG') - @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.STLError', - new_callable=lambda: MockError) - def test__connect_with_failures(self, mock_error, *args): + @mock.patch.object(sample_vnf, 'STLError') + def test__connect_with_failures(self, mock_stl_error, *args): vnfd_helper = VnfdHelper(self.VNFD_0) ssh_helper = mock.Mock() scenario_helper = mock.Mock() dpdk_setup_helper = DpdkVnfSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper) client_resource_helper = ClientResourceHelper(dpdk_setup_helper) client = mock.MagicMock() - client.connect.side_effect = mock_error + client.connect.side_effect = mock_stl_error(msg='msg') self.assertIs(client_resource_helper._connect(client), client) + @mock.patch.object(ClientResourceHelper, '_build_ports') + @mock.patch.object(ClientResourceHelper, '_run_traffic_once') + def test_run_traffic(self, mock_run_traffic_once, mock_build_ports): + client_resource_helper = ClientResourceHelper(mock.Mock()) + client = mock.Mock() + traffic_profile = mock.Mock() + mq_producer = mock.Mock() + with mock.patch.object(client_resource_helper, '_connect') \ + as mock_connect, \ + mock.patch.object(client_resource_helper, '_terminated') \ + as mock_terminated: + mock_connect.return_value = client + type(mock_terminated).value = mock.PropertyMock( + side_effect=[0, 1, lambda x: x]) + client_resource_helper.run_traffic(traffic_profile, mq_producer) + + mock_build_ports.assert_called_once() + traffic_profile.register_generator.assert_called_once() + mq_producer.tg_method_started.assert_called_once() + mq_producer.tg_method_finished.assert_called_once() + mq_producer.tg_method_iteration.assert_called_once_with(1) + mock_run_traffic_once.assert_called_once_with(traffic_profile) + + @mock.patch.object(ClientResourceHelper, '_build_ports') + @mock.patch.object(ClientResourceHelper, '_run_traffic_once', + side_effect=Exception) + def test_run_traffic_exception(self, mock_run_traffic_once, + mock_build_ports): + client_resource_helper = ClientResourceHelper(mock.Mock()) + client = mock.Mock() + traffic_profile = mock.Mock() + mq_producer = mock.Mock() + with mock.patch.object(client_resource_helper, '_connect') \ + as mock_connect, \ + mock.patch.object(client_resource_helper, '_terminated') \ + as mock_terminated: + mock_connect.return_value = client + type(mock_terminated).value = mock.PropertyMock(return_value=0) + mq_producer.reset_mock() + # NOTE(ralonsoh): "trex_stl_exceptions.STLError" is mocked + with self.assertRaises(Exception): + client_resource_helper.run_traffic(traffic_profile, + mq_producer) + + mock_build_ports.assert_called_once() + traffic_profile.register_generator.assert_called_once() + mock_run_traffic_once.assert_called_once_with(traffic_profile) + mq_producer.tg_method_started.assert_called_once() + mq_producer.tg_method_finished.assert_not_called() + mq_producer.tg_method_iteration.assert_not_called() + class TestRfc2544ResourceHelper(unittest.TestCase): @@ -1402,7 +1313,7 @@ class TestSampleVNFDeployHelper(unittest.TestCase): self.assertIsNone(sample_vnf_deploy_helper.deploy_vnfs('name1')) sample_vnf_deploy_helper.DISABLE_DEPLOY = True self.assertEqual(ssh_helper.execute.call_count, 5) - self.assertEqual(ssh_helper.put.call_count, 1) + ssh_helper.put.assert_called_once() @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.time') @mock.patch('subprocess.check_output') @@ -1417,7 +1328,7 @@ class TestSampleVNFDeployHelper(unittest.TestCase): self.assertIsNone(sample_vnf_deploy_helper.deploy_vnfs('name1')) self.assertEqual(ssh_helper.execute.call_count, 5) - self.assertEqual(ssh_helper.put.call_count, 1) + ssh_helper.put.assert_called_once() @mock.patch('subprocess.check_output') def test_deploy_vnfs_early_success(self, *args): @@ -1430,8 +1341,8 @@ class TestSampleVNFDeployHelper(unittest.TestCase): sample_vnf_deploy_helper.DISABLE_DEPLOY = False self.assertIsNone(sample_vnf_deploy_helper.deploy_vnfs('name1')) - self.assertEqual(ssh_helper.execute.call_count, 1) - self.assertEqual(ssh_helper.put.call_count, 0) + ssh_helper.execute.assert_called_once() + ssh_helper.put.assert_not_called() class TestScenarioHelper(unittest.TestCase): @@ -1632,7 +1543,7 @@ class TestSampleVnf(unittest.TestCase): } def test___init__(self): - sample_vnf = SampleVNF('vnf1', self.VNFD_0) + sample_vnf = SampleVNF('vnf1', self.VNFD_0, 'task_id') self.assertEqual(sample_vnf.name, 'vnf1') self.assertDictEqual(sample_vnf.vnfd_helper, self.VNFD_0) @@ -1650,7 +1561,8 @@ class TestSampleVnf(unittest.TestCase): class MyResourceHelper(ResourceHelper): pass - sample_vnf = SampleVNF('vnf1', self.VNFD_0, MySetupEnvHelper, MyResourceHelper) + sample_vnf = SampleVNF('vnf1', self.VNFD_0, 'task_id', + MySetupEnvHelper, MyResourceHelper) self.assertEqual(sample_vnf.name, 'vnf1') self.assertDictEqual(sample_vnf.vnfd_helper, self.VNFD_0) @@ -1664,7 +1576,7 @@ class TestSampleVnf(unittest.TestCase): @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.Process') def test__start_vnf(self, *args): vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - sample_vnf = SampleVNF('vnf1', vnfd) + sample_vnf = SampleVNF('vnf1', vnfd, 'task_id') sample_vnf._run = mock.Mock() self.assertIsNone(sample_vnf.queue_wrapper) @@ -1673,33 +1585,20 @@ class TestSampleVnf(unittest.TestCase): self.assertIsNotNone(sample_vnf.queue_wrapper) self.assertIsNotNone(sample_vnf._vnf_process) + @mock.patch.object(ctx_base.Context, 'get_context_from_server', return_value='fake_context') @mock.patch("yardstick.ssh.SSH") - def test_instantiate(self, ssh): - mock_ssh(ssh) - + def test_instantiate(self, ssh, *args): + test_base.mock_ssh(ssh) nodes = { 'vnf1': 'name1', 'vnf2': 'name2', } - context1 = mock.Mock() - context1._get_server.return_value = None - context2 = mock.Mock() - context2._get_server.return_value = context2 - - try: - Context.list.clear() - except AttributeError: - # clear() but works in Py2.7 - Context.list[:] = [] - - Context.list.extend([ - context1, - context2, - ]) - vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - sample_vnf = SampleVNF('vnf1', vnfd) + sample_vnf = SampleVNF('vnf1', vnfd, 'task_id') + sample_vnf.scenario_helper.scenario_cfg = { + 'nodes': {sample_vnf.name: 'mock'} + } sample_vnf.APP_NAME = 'sample1' sample_vnf._start_server = mock.Mock(return_value=0) sample_vnf._vnf_process = mock.MagicMock() @@ -1712,7 +1611,6 @@ class TestSampleVnf(unittest.TestCase): } self.assertIsNone(sample_vnf.instantiate(scenario_cfg, {})) - self.assertEqual(sample_vnf.nfvi_context, context2) def test__update_collectd_options(self): scenario_cfg = {'options': @@ -1741,7 +1639,7 @@ class TestSampleVnf(unittest.TestCase): 'plugin1': {'param': 1}}} vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - sample_vnf = SampleVNF('vnf__0', vnfd) + sample_vnf = SampleVNF('vnf__0', vnfd, 'task_id') sample_vnf._update_collectd_options(scenario_cfg, context_cfg) self.assertEqual(sample_vnf.setup_helper.collectd_options, expected) @@ -1768,14 +1666,14 @@ class TestSampleVnf(unittest.TestCase): 'plugin1': {'param': 1}}} vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - sample_vnf = SampleVNF('vnf1', vnfd) + sample_vnf = SampleVNF('vnf1', vnfd, 'task_id') sample_vnf._update_options(options2, options1) self.assertEqual(options2, expected) @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.time") @mock.patch("yardstick.ssh.SSH") def test_wait_for_instantiate_empty_queue(self, ssh, *args): - mock_ssh(ssh, exec_result=(1, "", "")) + test_base.mock_ssh(ssh, exec_result=(1, "", "")) queue_size_list = [ 0, @@ -1790,7 +1688,7 @@ class TestSampleVnf(unittest.TestCase): ] vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - sample_vnf = SampleVNF('vnf1', vnfd) + sample_vnf = SampleVNF('vnf1', vnfd, 'task_id') sample_vnf.APP_NAME = 'sample1' sample_vnf.WAIT_TIME_FOR_SCRIPT = 0 sample_vnf._start_server = mock.Mock(return_value=0) @@ -1821,7 +1719,7 @@ class TestSampleVnf(unittest.TestCase): ] vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - sample_vnf = SampleVNF('vnf1', vnfd) + sample_vnf = SampleVNF('vnf1', vnfd, 'task_id') sample_vnf.APP_NAME = 'sample1' sample_vnf.q_out = mock.Mock() sample_vnf.q_out.qsize.side_effect = iter(queue_size_list) @@ -1831,7 +1729,7 @@ class TestSampleVnf(unittest.TestCase): def test_terminate_without_vnf_process(self): vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - sample_vnf = SampleVNF('vnf1', vnfd) + sample_vnf = SampleVNF('vnf1', vnfd, 'task_id') sample_vnf.APP_NAME = 'sample1' sample_vnf.vnf_execute = mock.Mock() sample_vnf.ssh_helper = mock.Mock() @@ -1842,16 +1740,20 @@ class TestSampleVnf(unittest.TestCase): def test_get_stats(self): vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - sample_vnf = SampleVNF('vnf1', vnfd) + sample_vnf = SampleVNF('vnf1', vnfd, 'task_id') sample_vnf.APP_NAME = 'sample1' sample_vnf.APP_WORD = 'sample1' sample_vnf.vnf_execute = mock.Mock(return_value='the stats') self.assertEqual(sample_vnf.get_stats(), 'the stats') - def test_collect_kpi(self): + @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', return_value='mock_node') + def test_collect_kpi(self, *args): vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - sample_vnf = SampleVNF('vnf1', vnfd) + sample_vnf = SampleVNF('vnf1', vnfd, 'task_id') + sample_vnf.scenario_helper.scenario_cfg = { + 'nodes': {sample_vnf.name: "mock"} + } sample_vnf.APP_NAME = 'sample1' sample_vnf.COLLECT_KPI = r'\s(\d+)\D*(\d+)\D*(\d+)' sample_vnf.COLLECT_MAP = { @@ -1868,18 +1770,24 @@ class TestSampleVnf(unittest.TestCase): 'k2': 34, 'k3': 91, 'collect_stats': {}, + 'physical_node': 'mock_node' } result = sample_vnf.collect_kpi() self.assertDictEqual(result, expected) - def test_collect_kpi_default(self): + @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', return_value='mock_node') + def test_collect_kpi_default(self, *args): vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - sample_vnf = SampleVNF('vnf1', vnfd) + sample_vnf = SampleVNF('vnf1', vnfd, 'task_id') + sample_vnf.scenario_helper.scenario_cfg = { + 'nodes': {sample_vnf.name: "mock"} + } sample_vnf.APP_NAME = 'sample1' sample_vnf.COLLECT_KPI = r'\s(\d+)\D*(\d+)\D*(\d+)' sample_vnf.get_stats = mock.Mock(return_value='') expected = { + 'physical_node': 'mock_node', 'packets_in': 0, 'packets_fwd': 0, 'packets_dropped': 0, @@ -1889,7 +1797,7 @@ class TestSampleVnf(unittest.TestCase): def test_scale(self): vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - sample_vnf = SampleVNF('vnf1', vnfd) + sample_vnf = SampleVNF('vnf1', vnfd, 'task_id') self.assertRaises(y_exceptions.FunctionNotImplemented, sample_vnf.scale) @@ -1897,7 +1805,7 @@ class TestSampleVnf(unittest.TestCase): test_cmd = 'test cmd' run_kwargs = {'arg1': 'val1', 'arg2': 'val2'} vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - sample_vnf = SampleVNF('vnf1', vnfd) + sample_vnf = SampleVNF('vnf1', vnfd, 'task_id') sample_vnf.ssh_helper = mock.Mock() sample_vnf.setup_helper = mock.Mock() with mock.patch.object(sample_vnf, '_build_config', @@ -2033,30 +1941,30 @@ class TestSampleVNFTrafficGen(unittest.TestCase): } def test__check_status(self): - sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0) + sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0, 'task_id') with self.assertRaises(NotImplementedError): sample_vnf_tg._check_status() def test_listen_traffic(self): - sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0) + sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0, 'task_id') sample_vnf_tg.listen_traffic(mock.Mock()) def test_verify_traffic(self): - sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0) + sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0, 'task_id') sample_vnf_tg.verify_traffic(mock.Mock()) def test_terminate(self): - sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0) + sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0, 'task_id') sample_vnf_tg._traffic_process = mock.Mock() sample_vnf_tg._tg_process = mock.Mock() sample_vnf_tg.terminate() def test__wait_for_process(self): - sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0) + sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0, 'task_id') with mock.patch.object(sample_vnf_tg, '_check_status', return_value=0) as mock_status, \ mock.patch.object(sample_vnf_tg, '_tg_process') as mock_proc: @@ -2067,14 +1975,14 @@ class TestSampleVNFTrafficGen(unittest.TestCase): mock_status.assert_called_once() def test__wait_for_process_not_alive(self): - sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0) + sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0, 'task_id') with mock.patch.object(sample_vnf_tg, '_tg_process') as mock_proc: mock_proc.is_alive.return_value = False self.assertRaises(RuntimeError, sample_vnf_tg._wait_for_process) mock_proc.is_alive.assert_called_once() def test__wait_for_process_delayed(self): - sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0) + sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0, 'task_id') with mock.patch.object(sample_vnf_tg, '_check_status', side_effect=[1, 0]) as mock_status, \ mock.patch.object(sample_vnf_tg, @@ -2086,6 +1994,6 @@ class TestSampleVNFTrafficGen(unittest.TestCase): mock_status.assert_has_calls([mock.call(), mock.call()]) def test_scale(self): - sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0) + sample_vnf_tg = SampleVNFTrafficGen('tg1', self.VNFD_0, 'task_id') self.assertRaises(y_exceptions.FunctionNotImplemented, sample_vnf_tg.scale) diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_ixload.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_ixload.py new file mode 100644 index 000000000..53474b96e --- /dev/null +++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_ixload.py @@ -0,0 +1,271 @@ +# Copyright (c) 2016-2017 Intel Corporation +# +# 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. + +import subprocess + +import mock +import six + +from yardstick import ssh +from yardstick.benchmark.contexts import base as ctx_base +from yardstick.common import utils +from yardstick.network_services.vnf_generic.vnf import tg_ixload +from yardstick.network_services.traffic_profile import base as tp_base +from yardstick.tests.unit import base as ut_base + + +NAME = "tg__1" + + +class TestIxLoadTrafficGen(ut_base.BaseUnitTestCase): + VNFD = {'vnfd:vnfd-catalog': + {'vnfd': + [{'short-name': 'VpeVnf', + 'vdu': + [{'routing_table': + [{'network': '152.16.100.20', + 'netmask': '255.255.255.0', + 'gateway': '152.16.100.20', + 'if': 'xe0'}, + {'network': '152.16.40.20', + 'netmask': '255.255.255.0', + 'gateway': '152.16.40.20', + 'if': 'xe1'}], + 'description': 'VPE approximation using DPDK', + 'name': 'vpevnf-baremetal', + 'nd_route_tbl': + [{'network': '0064:ff9b:0:0:0:0:9810:6414', + 'netmask': '112', + 'gateway': '0064:ff9b:0:0:0:0:9810:6414', + 'if': 'xe0'}, + {'network': '0064:ff9b:0:0:0:0:9810:2814', + 'netmask': '112', + 'gateway': '0064:ff9b:0:0:0:0:9810:2814', + 'if': 'xe1'}], + 'id': 'vpevnf-baremetal', + 'external-interface': + [{'virtual-interface': + {'dst_mac': '00:00:00:00:00:04', + 'vpci': '0000:05:00.0', + 'local_ip': '152.16.100.19', + 'type': 'PCI-PASSTHROUGH', + 'netmask': '255.255.255.0', + 'dpdk_port_num': 0, + 'bandwidth': '10 Gbps', + 'driver': "i40e", + 'dst_ip': '152.16.100.20', + 'local_iface_name': 'xe0', + 'local_mac': '00:00:00:00:00:02'}, + 'vnfd-connection-point-ref': 'xe0', + 'name': 'xe0'}, + {'virtual-interface': + {'dst_mac': '00:00:00:00:00:03', + 'vpci': '0000:05:00.1', + 'local_ip': '152.16.40.19', + 'type': 'PCI-PASSTHROUGH', + 'driver': "i40e", + 'netmask': '255.255.255.0', + 'dpdk_port_num': 1, + 'bandwidth': '10 Gbps', + 'dst_ip': '152.16.40.20', + 'local_iface_name': 'xe1', + 'local_mac': '00:00:00:00:00:01'}, + 'vnfd-connection-point-ref': 'xe1', + 'name': 'xe1'}]}], + 'description': 'Vpe approximation using DPDK', + 'mgmt-interface': + {'vdu-id': 'vpevnf-baremetal', + 'host': '1.1.1.1', + 'password': 'r00t', + 'user': 'root', + 'ip': '1.1.1.1'}, + 'benchmark': + {'kpi': ['packets_in', 'packets_fwd', 'packets_dropped']}, + 'connection-point': [{'type': 'VPORT', 'name': 'xe0'}, + {'type': 'VPORT', 'name': 'xe1'}], + 'id': 'VpeApproxVnf', 'name': 'VPEVnfSsh'}]}} + + TRAFFIC_PROFILE = { + "schema": "isb:traffic_profile:0.1", + "name": "fixed", + "description": "Fixed traffic profile to run UDP traffic", + "traffic_profile": { + "traffic_type": "FixedTraffic", + "frame_rate": 100, # pps + "flow_number": 10, + "frame_size": 64}} + + def setUp(self): + self._mock_call = mock.patch.object(subprocess, 'call') + self.mock_call = self._mock_call.start() + self._mock_open = mock.patch.object(tg_ixload, 'open') + self.mock_open = self._mock_open.start() + self._mock_ssh = mock.patch.object(ssh, 'SSH') + self.mock_ssh = self._mock_ssh.start() + ssh_obj_mock = mock.Mock(autospec=ssh.SSH) + ssh_obj_mock.execute = mock.Mock(return_value=(0, '', '')) + ssh_obj_mock.run = mock.Mock(return_value=(0, '', '')) + self.mock_ssh.from_node.return_value = ssh_obj_mock + self.addCleanup(self._stop_mock) + + def _stop_mock(self): + self._mock_call.stop() + self._mock_open.stop() + self._mock_ssh.stop() + + def test___init__(self): + vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] + ixload_traffic_gen = tg_ixload.IxLoadTrafficGen(NAME, vnfd, 'task_id') + self.assertIsNone(ixload_traffic_gen.resource_helper.data) + + @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', + return_value='mock_node') + def test_collect_kpi(self, *args): + vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] + ixload_traffic_gen = tg_ixload.IxLoadTrafficGen(NAME, vnfd, 'task_id') + ixload_traffic_gen.scenario_helper.scenario_cfg = { + 'nodes': {ixload_traffic_gen.name: "mock"} + } + ixload_traffic_gen.data = {} + result = ixload_traffic_gen.collect_kpi() + + expected = { + 'physical_node': 'mock_node', + 'collect_stats': {}} + self.assertEqual(expected, result) + + def test_listen_traffic(self): + vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] + ixload_traffic_gen = tg_ixload.IxLoadTrafficGen(NAME, vnfd, 'task_id') + self.assertIsNone(ixload_traffic_gen.listen_traffic({})) + + @mock.patch.object(utils, 'find_relative_file') + @mock.patch.object(utils, 'makedirs') + @mock.patch.object(ctx_base.Context, 'get_context_from_server') + @mock.patch.object(tg_ixload, 'shutil') + def test_instantiate(self, mock_shutil, *args): + vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] + ixload_traffic_gen = tg_ixload.IxLoadTrafficGen(NAME, vnfd, 'task_id') + scenario_cfg = {'tc': "nsb_test_case", + 'ixia_profile': "ixload.cfg", + 'task_path': "/path/to/task"} + ixload_traffic_gen.RESULTS_MOUNT = "/tmp/result" + mock_shutil.copy = mock.Mock() + scenario_cfg.update( + {'options': + {'packetsize': 64, 'traffic_type': 4, + 'rfc2544': {'allowed_drop_rate': '0.8 - 1'}, + 'vnf__1': {'rules': 'acl_1rule.yaml', + 'vnf_config': {'lb_config': 'SW', + 'lb_count': 1, + 'worker_config': + '1C/1T', + 'worker_threads': 1}} + } + } + ) + scenario_cfg.update({'nodes': {ixload_traffic_gen.name: "mock"}}) + with mock.patch.object(six.moves.builtins, 'open', + create=True) as mock_open: + mock_open.return_value = mock.MagicMock() + ixload_traffic_gen.instantiate(scenario_cfg, {}) + + @mock.patch.object(tg_ixload, 'open') + @mock.patch.object(tg_ixload, 'min') + @mock.patch.object(tg_ixload, 'max') + @mock.patch.object(tg_ixload, 'len') + @mock.patch.object(tg_ixload, 'shutil') + def test_run_traffic(self, *args): + mock_traffic_profile = mock.Mock(autospec=tp_base.TrafficProfile) + mock_traffic_profile.get_traffic_definition.return_value = '64' + mock_traffic_profile.params = self.TRAFFIC_PROFILE + vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] + vnfd['mgmt-interface'].update({'tg-config': {}}) + vnfd['mgmt-interface']['tg-config'].update({'ixchassis': '1.1.1.1'}) + vnfd['mgmt-interface']['tg-config'].update({'py_bin_path': '/root'}) + sut = tg_ixload.IxLoadTrafficGen(NAME, vnfd, 'task_id') + sut.connection = mock.Mock() + sut._traffic_runner = mock.Mock(return_value=0) + result = sut.run_traffic(mock_traffic_profile) + self.assertIsNone(result) + + @mock.patch.object(tg_ixload, 'open') + @mock.patch.object(tg_ixload, 'min') + @mock.patch.object(tg_ixload, 'max') + @mock.patch.object(tg_ixload, 'len') + @mock.patch.object(tg_ixload, 'shutil') + def test_run_traffic_csv(self, *args): + mock_traffic_profile = mock.Mock(autospec=tp_base.TrafficProfile) + mock_traffic_profile.get_traffic_definition.return_value = '64' + mock_traffic_profile.params = self.TRAFFIC_PROFILE + vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] + vnfd['mgmt-interface'].update({'tg-config': {}}) + vnfd['mgmt-interface']['tg-config'].update({'ixchassis': '1.1.1.1'}) + vnfd['mgmt-interface']['tg-config'].update({'py_bin_path': '/root'}) + sut = tg_ixload.IxLoadTrafficGen(NAME, vnfd, 'task_id') + sut.connection = mock.Mock() + sut._traffic_runner = mock.Mock(return_value=0) + subprocess.call(['touch', '/tmp/1.csv']) + sut.rel_bin_path = mock.Mock(return_value='/tmp/*.csv') + result = sut.run_traffic(mock_traffic_profile) + self.assertIsNone(result) + + def test_terminate(self): + vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] + ixload_traffic_gen = tg_ixload.IxLoadTrafficGen(NAME, vnfd, 'task_id') + self.assertIsNone(ixload_traffic_gen.terminate()) + + def test_parse_csv_read(self): + vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] + kpi_data = { + 'HTTP Total Throughput (Kbps)': 1, + 'HTTP Simulated Users': 2, + 'HTTP Concurrent Connections': '3', + 'HTTP Connection Rate': 4.3, + 'HTTP Transaction Rate': True, + } + http_reader = [kpi_data] + ixload_traffic_gen = tg_ixload.IxLoadTrafficGen(NAME, vnfd, 'task_id') + result = ixload_traffic_gen.resource_helper.result + ixload_traffic_gen.resource_helper.parse_csv_read(http_reader) + for k_left, k_right in tg_ixload.IxLoadResourceHelper.KPI_LIST.items(): + self.assertEqual(result[k_left][-1], int(kpi_data[k_right])) + + def test_parse_csv_read_value_error(self): + vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] + http_reader = [{ + 'HTTP Total Throughput (Kbps)': 1, + 'HTTP Simulated Users': 2, + 'HTTP Concurrent Connections': "not a number", + 'HTTP Connection Rate': 4, + 'HTTP Transaction Rate': 5, + }] + ixload_traffic_gen = tg_ixload.IxLoadTrafficGen(NAME, vnfd, 'task_id') + init_value = ixload_traffic_gen.resource_helper.result + ixload_traffic_gen.resource_helper.parse_csv_read(http_reader) + self.assertDictEqual(ixload_traffic_gen.resource_helper.result, + init_value) + + def test_parse_csv_read_error(self,): + vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] + http_reader = [{ + 'HTTP Total Throughput (Kbps)': 1, + 'HTTP Simulated Users': 2, + 'HTTP Concurrent Connections': 3, + 'HTTP Transaction Rate': 5, + }] + ixload_traffic_gen = tg_ixload.IxLoadTrafficGen(NAME, vnfd, 'task_id') + + with self.assertRaises(KeyError): + ixload_traffic_gen.resource_helper.parse_csv_read(http_reader) diff --git a/tests/unit/network_services/vnf_generic/vnf/test_tg_ping.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_ping.py index 91a353d0d..434a7b770 100644 --- a/tests/unit/network_services/vnf_generic/vnf/test_tg_ping.py +++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_ping.py @@ -13,28 +13,22 @@ # limitations under the License. # -from __future__ import absolute_import - -import unittest -import mock from multiprocessing import Queue import multiprocessing -from tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh -from tests.unit import STL_MOCKS +import mock +import unittest -SSH_HELPER = "yardstick.network_services.vnf_generic.vnf.sample_vnf.VnfSshHelper" +from yardstick.tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh +from yardstick.benchmark.contexts import base as ctx_base +from yardstick.network_services.vnf_generic.vnf.tg_ping import PingParser +from yardstick.network_services.vnf_generic.vnf.tg_ping import PingTrafficGen +from yardstick.network_services.vnf_generic.vnf.tg_ping import PingResourceHelper +from yardstick.network_services.vnf_generic.vnf.tg_ping import PingSetupEnvHelper +from yardstick.network_services.vnf_generic.vnf.vnf_ssh_helper import VnfSshHelper -STLClient = mock.MagicMock() -stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) -stl_patch.start() -if stl_patch: - from yardstick.network_services.vnf_generic.vnf.tg_ping import PingParser - from yardstick.network_services.vnf_generic.vnf.tg_ping import PingTrafficGen - from yardstick.network_services.vnf_generic.vnf.tg_ping import PingResourceHelper - from yardstick.network_services.vnf_generic.vnf.tg_ping import PingSetupEnvHelper - from yardstick.network_services.vnf_generic.vnf.vnf_ssh_helper import VnfSshHelper +SSH_HELPER = "yardstick.network_services.vnf_generic.vnf.sample_vnf.VnfSshHelper" class TestPingResourceHelper(unittest.TestCase): @@ -232,7 +226,7 @@ class TestPingTrafficGen(unittest.TestCase): @mock.patch("yardstick.ssh.SSH") def test___init__(self, ssh): ssh.from_node.return_value.execute.return_value = 0, "success", "" - ping_traffic_gen = PingTrafficGen('vnf1', self.VNFD_0) + ping_traffic_gen = PingTrafficGen('vnf1', self.VNFD_0, 'task_id') self.assertIsInstance(ping_traffic_gen.setup_helper, PingSetupEnvHelper) self.assertIsInstance(ping_traffic_gen.resource_helper, PingResourceHelper) @@ -249,24 +243,35 @@ class TestPingTrafficGen(unittest.TestCase): (0, 'if_name_2', ''), ] ssh.from_node.return_value.execute.side_effect = iter(execute_result_data) - ping_traffic_gen = PingTrafficGen('vnf1', self.VNFD_0) + ping_traffic_gen = PingTrafficGen('vnf1', self.VNFD_0, 'task_id') ext_ifs = ping_traffic_gen.vnfd_helper.interfaces self.assertNotEqual(ext_ifs[0]['virtual-interface']['local_iface_name'], 'if_name_1') self.assertNotEqual(ext_ifs[1]['virtual-interface']['local_iface_name'], 'if_name_2') + @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', return_value='mock_node') @mock.patch("yardstick.ssh.SSH") - def test_collect_kpi(self, ssh): + def test_collect_kpi(self, ssh, *args): mock_ssh(ssh, exec_result=(0, "success", "")) - ping_traffic_gen = PingTrafficGen('vnf1', self.VNFD_0) + + ping_traffic_gen = PingTrafficGen('vnf1', self.VNFD_0, 'task_id') + ping_traffic_gen.scenario_helper.scenario_cfg = { + 'nodes': {ping_traffic_gen.name: "mock"} + } ping_traffic_gen._queue = Queue() ping_traffic_gen._queue.put({}) - ping_traffic_gen.collect_kpi() - self.assertEqual(ping_traffic_gen._result, {}) + expected = { + 'physical_node': 'mock_node', + 'collect_stats': {} + } + # NOTE: Why we check _result but not collect_kpi() return value + # self.assertEqual(ping_traffic_gen._result, {}) + self.assertEqual(ping_traffic_gen.collect_kpi(), expected) + @mock.patch(SSH_HELPER) def test_instantiate(self, ssh): mock_ssh(ssh, spec=VnfSshHelper, exec_result=(0, "success", "")) - ping_traffic_gen = PingTrafficGen('vnf1', self.VNFD_0) + ping_traffic_gen = PingTrafficGen('vnf1', self.VNFD_0, 'task_id') ping_traffic_gen.setup_helper.ssh_helper = mock.MagicMock( **{"execute.return_value": (0, "xe0_fake", "")}) self.assertIsInstance(ping_traffic_gen.ssh_helper, mock.Mock) @@ -281,7 +286,7 @@ class TestPingTrafficGen(unittest.TestCase): self.assertIsNotNone(ping_traffic_gen._result) def test_listen_traffic(self): - ping_traffic_gen = PingTrafficGen('vnf1', self.VNFD_0) + ping_traffic_gen = PingTrafficGen('vnf1', self.VNFD_0, 'task_id') self.assertIsNone(ping_traffic_gen.listen_traffic({})) @mock.patch("yardstick.ssh.SSH") @@ -289,5 +294,5 @@ class TestPingTrafficGen(unittest.TestCase): ssh.from_node.return_value.execute.return_value = 0, "success", "" ssh.from_node.return_value.run.return_value = 0, "success", "" - ping_traffic_gen = PingTrafficGen('vnf1', self.VNFD_0) + ping_traffic_gen = PingTrafficGen('vnf1', self.VNFD_0, 'task_id') self.assertIsNone(ping_traffic_gen.terminate()) diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_pktgen.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_pktgen.py new file mode 100644 index 000000000..d341b970b --- /dev/null +++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_pktgen.py @@ -0,0 +1,79 @@ +# Copyright (c) 2018 Intel Corporation +# +# 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. + +import uuid + +import mock + +from yardstick.common import constants +from yardstick.common import exceptions +from yardstick.network_services.vnf_generic.vnf import base as vnf_base +from yardstick.network_services.vnf_generic.vnf import tg_pktgen +from yardstick.tests.unit import base as ut_base + + +class PktgenTrafficGenTestCase(ut_base.BaseUnitTestCase): + + SERVICE_PORTS = [{'port': constants.LUA_PORT, + 'node_port': '34501'}] + VNFD = {'mgmt-interface': {'ip': '1.2.3.4', + 'service_ports': SERVICE_PORTS}, + 'vdu': [{'external-interface': 'interface'}], + 'benchmark': {'kpi': 'fake_kpi'} + } + + def setUp(self): + self._id = uuid.uuid1().int + self._mock_vnf_consumer = mock.patch.object(vnf_base, + 'GenericVNFConsumer') + self.mock_vnf_consumer = self._mock_vnf_consumer.start() + self.addCleanup(self._stop_mock) + + def _stop_mock(self): + self._mock_vnf_consumer.stop() + + def test__init(self): + tg = tg_pktgen.PktgenTrafficGen('name1', self.VNFD, self._id) + self.assertTrue(isinstance(tg, (vnf_base.GenericTrafficGen, + vnf_base.GenericVNFEndpoint))) + + def test_run_traffic(self): + tg = tg_pktgen.PktgenTrafficGen('name1', self.VNFD, self._id) + mock_tp = mock.Mock() + with mock.patch.object(tg, '_is_running', return_value=True): + tg.run_traffic(mock_tp) + + mock_tp.init.assert_called_once_with(tg._node_ip, tg._lua_node_port) + + def test__get_lua_node_port(self): + tg = tg_pktgen.PktgenTrafficGen('name1', self.VNFD, self._id) + service_ports = [{'port': constants.LUA_PORT, + 'node_port': '12345'}] + self.assertEqual(12345, tg._get_lua_node_port(service_ports)) + + def test__get_lua_node_port_no_lua_port(self): + tg = tg_pktgen.PktgenTrafficGen('name1', self.VNFD, self._id) + service_ports = [{'port': '333'}] + self.assertIsNone(tg._get_lua_node_port(service_ports)) + + def test__is_running(self): + tg = tg_pktgen.PktgenTrafficGen('name1', self.VNFD, self._id) + with mock.patch.object(tg, '_traffic_profile'): + self.assertTrue(tg._is_running()) + + def test__is_running_exception(self): + tg = tg_pktgen.PktgenTrafficGen('name1', self.VNFD, self._id) + with mock.patch.object(tg, '_traffic_profile') as mock_tp: + mock_tp.help.side_effect = exceptions.PktgenActionError() + self.assertFalse(tg._is_running()) diff --git a/tests/unit/network_services/vnf_generic/vnf/test_tg_prox.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_prox.py index 2151a3284..5ad182f22 100644 --- a/tests/unit/network_services/vnf_generic/vnf/test_tg_prox.py +++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_prox.py @@ -16,21 +16,15 @@ import unittest import mock -from tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh -from tests.unit import STL_MOCKS +from yardstick.tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh +from yardstick.benchmark.contexts import base as ctx_base +from yardstick.network_services.vnf_generic.vnf.tg_prox import ProxTrafficGen +from yardstick.network_services.traffic_profile.base import TrafficProfile SSH_HELPER = 'yardstick.network_services.vnf_generic.vnf.sample_vnf.VnfSshHelper' NAME = 'vnf__1' -STLClient = mock.MagicMock() -stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) -stl_patch.start() - -if stl_patch: - from yardstick.network_services.vnf_generic.vnf.tg_prox import ProxTrafficGen - from yardstick.network_services.traffic_profile.base import TrafficProfile - @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.time') class TestProxTrafficGen(unittest.TestCase): @@ -320,19 +314,26 @@ class TestProxTrafficGen(unittest.TestCase): @mock.patch(SSH_HELPER) def test___init__(self, ssh, *args): mock_ssh(ssh) - prox_traffic_gen = ProxTrafficGen(NAME, self.VNFD0) + prox_traffic_gen = ProxTrafficGen(NAME, self.VNFD0, 'task_id') self.assertIsNone(prox_traffic_gen._tg_process) self.assertIsNone(prox_traffic_gen._traffic_process) + @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', return_value='mock_node') @mock.patch(SSH_HELPER) def test_collect_kpi(self, ssh, *args): mock_ssh(ssh) - - prox_traffic_gen = ProxTrafficGen(NAME, self.VNFD0) + prox_traffic_gen = ProxTrafficGen(NAME, self.VNFD0, 'task_id') + prox_traffic_gen.scenario_helper.scenario_cfg = { + 'nodes': {prox_traffic_gen.name: "mock"} + } prox_traffic_gen._vnf_wrapper.resource_helper.resource = mock.MagicMock( **{"self.check_if_system_agent_running.return_value": [False]}) prox_traffic_gen._vnf_wrapper.vnf_execute = mock.Mock(return_value="") - self.assertEqual({}, prox_traffic_gen.collect_kpi()) + expected = { + 'collect_stats': {}, + 'physical_node': 'mock_node' + } + self.assertEqual(prox_traffic_gen.collect_kpi(), expected) @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.find_relative_file') @@ -349,7 +350,7 @@ class TestProxTrafficGen(unittest.TestCase): mock_traffic_profile.params = self.TRAFFIC_PROFILE vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - prox_traffic_gen = ProxTrafficGen(NAME, vnfd) + prox_traffic_gen = ProxTrafficGen(NAME, vnfd, 'task_id') ssh_helper = mock.MagicMock( **{"execute.return_value": (0, "", ""), "bin_path": ""}) prox_traffic_gen.ssh_helper = ssh_helper @@ -391,21 +392,22 @@ class TestProxTrafficGen(unittest.TestCase): mock_traffic_profile.params = self.TRAFFIC_PROFILE vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - sut = ProxTrafficGen(NAME, vnfd) + sut = ProxTrafficGen(NAME, vnfd, 'task_id') sut._get_socket = mock.MagicMock() sut.ssh_helper = mock.Mock() sut.ssh_helper.run = mock.Mock() sut.setup_helper.prox_config_dict = {} - sut._connect_client = mock.Mock(autospec=STLClient) + sut._connect_client = mock.Mock(autospec=mock.Mock()) sut._connect_client.get_stats = mock.Mock(return_value="0") - sut._traffic_runner(mock_traffic_profile) + sut._setup_mq_producer = mock.Mock(return_value='mq_producer') + sut._traffic_runner(mock_traffic_profile, mock.ANY) @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.socket') @mock.patch(SSH_HELPER) def test_listen_traffic(self, ssh, *args): mock_ssh(ssh) vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - prox_traffic_gen = ProxTrafficGen(NAME, vnfd) + prox_traffic_gen = ProxTrafficGen(NAME, vnfd, 'task_id') self.assertIsNone(prox_traffic_gen.listen_traffic(mock.Mock())) @mock.patch('yardstick.network_services.vnf_generic.vnf.prox_helpers.socket') @@ -413,7 +415,7 @@ class TestProxTrafficGen(unittest.TestCase): def test_terminate(self, ssh, *args): mock_ssh(ssh) vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - prox_traffic_gen = ProxTrafficGen(NAME, vnfd) + prox_traffic_gen = ProxTrafficGen(NAME, vnfd, 'task_id') prox_traffic_gen._terminated = mock.MagicMock() prox_traffic_gen._traffic_process = mock.MagicMock() prox_traffic_gen._traffic_process.terminate = mock.Mock() diff --git a/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_ixia.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_ixia.py index 61fc012bc..ddb63242e 100644 --- a/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_ixia.py +++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_ixia.py @@ -11,7 +11,6 @@ # 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. -# import os @@ -19,57 +18,73 @@ import mock import six import unittest -from tests.unit import STL_MOCKS - -STLClient = mock.MagicMock() -stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) -stl_patch.start() +from yardstick.benchmark import contexts +from yardstick.benchmark.contexts import base as ctx_base +from yardstick.network_services.libs.ixia_libs.ixnet import ixnet_api +from yardstick.network_services.traffic_profile import base as tp_base +from yardstick.network_services.vnf_generic.vnf import tg_rfc2544_ixia -if stl_patch: - from yardstick.network_services.vnf_generic.vnf.tg_rfc2544_ixia import IxiaTrafficGen - from yardstick.network_services.vnf_generic.vnf.tg_rfc2544_ixia import IxiaRfc2544Helper - from yardstick.network_services.vnf_generic.vnf.tg_rfc2544_ixia import IxiaResourceHelper - from yardstick.network_services.traffic_profile.base import TrafficProfile TEST_FILE_YAML = 'nsb_test_case.yaml' NAME = "tg__1" -@mock.patch("yardstick.network_services.vnf_generic.vnf.tg_rfc2544_ixia.IxNextgen") class TestIxiaResourceHelper(unittest.TestCase): - def test___init___with_custom_rfc_helper(self, *args): - class MyRfcHelper(IxiaRfc2544Helper): + + def setUp(self): + self._mock_IxNextgen = mock.patch.object(ixnet_api, 'IxNextgen') + self.mock_IxNextgen = self._mock_IxNextgen.start() + self.addCleanup(self._stop_mocks) + + def _stop_mocks(self): + self._mock_IxNextgen.stop() + + def test___init___with_custom_rfc_helper(self): + class MyRfcHelper(tg_rfc2544_ixia.IxiaRfc2544Helper): pass - ixia_resource_helper = IxiaResourceHelper(mock.Mock(), MyRfcHelper) + ixia_resource_helper = tg_rfc2544_ixia.IxiaResourceHelper( + mock.Mock(), MyRfcHelper) self.assertIsInstance(ixia_resource_helper.rfc_helper, MyRfcHelper) - def test_stop_collect_with_client(self, *args): + def test_stop_collect_with_client(self): mock_client = mock.Mock() - - ixia_resource_helper = IxiaResourceHelper(mock.Mock()) - + ixia_resource_helper = tg_rfc2544_ixia.IxiaResourceHelper(mock.Mock()) ixia_resource_helper.client = mock_client ixia_resource_helper.stop_collect() - self.assertEqual(mock_client.ix_stop_traffic.call_count, 1) + self.assertEqual(1, ixia_resource_helper._terminated.value) + + def test_run_traffic(self): + mock_tprofile = mock.Mock() + mock_tprofile.get_drop_percentage.return_value = True, 'fake_samples' + ixia_rhelper = tg_rfc2544_ixia.IxiaResourceHelper(mock.Mock()) + ixia_rhelper.rfc_helper = mock.Mock() + ixia_rhelper.vnfd_helper = mock.Mock() + ixia_rhelper.vnfd_helper.port_pairs.all_ports = [] + with mock.patch.object(ixia_rhelper, 'generate_samples'), \ + mock.patch.object(ixia_rhelper, '_build_ports'), \ + mock.patch.object(ixia_rhelper, '_initialize_client'): + ixia_rhelper.run_traffic(mock_tprofile) + self.assertEqual('fake_samples', ixia_rhelper._queue.get()) -@mock.patch("yardstick.network_services.vnf_generic.vnf.tg_rfc2544_ixia.IxNextgen") + +@mock.patch.object(tg_rfc2544_ixia, 'ixnet_api') class TestIXIATrafficGen(unittest.TestCase): VNFD = {'vnfd:vnfd-catalog': - {'vnfd': - [{'short-name': 'VpeVnf', - 'vdu': - [{'routing_table': - [{'network': '152.16.100.20', - 'netmask': '255.255.255.0', - 'gateway': '152.16.100.20', - 'if': 'xe0'}, - {'network': '152.16.40.20', - 'netmask': '255.255.255.0', - 'gateway': '152.16.40.20', - 'if': 'xe1'}], + {'vnfd': + [{'short-name': 'VpeVnf', + 'vdu': + [{'routing_table': + [{'network': '152.16.100.20', + 'netmask': '255.255.255.0', + 'gateway': '152.16.100.20', + 'if': 'xe0'}, + {'network': '152.16.40.20', + 'netmask': '255.255.255.0', + 'gateway': '152.16.40.20', + 'if': 'xe1'}], 'description': 'VPE approximation using DPDK', 'name': 'vpevnf-baremetal', 'nd_route_tbl': @@ -84,45 +99,46 @@ class TestIXIATrafficGen(unittest.TestCase): 'id': 'vpevnf-baremetal', 'external-interface': [{'virtual-interface': - {'dst_mac': '00:00:00:00:00:04', - 'vpci': '0000:05:00.0', - 'local_ip': '152.16.100.19', - 'type': 'PCI-PASSTHROUGH', - 'netmask': '255.255.255.0', - 'dpdk_port_num': 0, - 'bandwidth': '10 Gbps', - 'driver': "i40e", - 'dst_ip': '152.16.100.20', - 'local_iface_name': 'xe0', - 'local_mac': '00:00:00:00:00:02'}, + {'dst_mac': '00:00:00:00:00:04', + 'vpci': '0000:05:00.0', + 'local_ip': '152.16.100.19', + 'type': 'PCI-PASSTHROUGH', + 'netmask': '255.255.255.0', + 'dpdk_port_num': 0, + 'bandwidth': '10 Gbps', + 'driver': "i40e", + 'dst_ip': '152.16.100.20', + 'local_iface_name': 'xe0', + 'local_mac': '00:00:00:00:00:02'}, 'vnfd-connection-point-ref': 'xe0', 'name': 'xe0'}, {'virtual-interface': - {'dst_mac': '00:00:00:00:00:03', - 'vpci': '0000:05:00.1', - 'local_ip': '152.16.40.19', - 'type': 'PCI-PASSTHROUGH', - 'driver': "i40e", - 'netmask': '255.255.255.0', - 'dpdk_port_num': 1, - 'bandwidth': '10 Gbps', - 'dst_ip': '152.16.40.20', - 'local_iface_name': 'xe1', - 'local_mac': '00:00:00:00:00:01'}, + {'dst_mac': '00:00:00:00:00:03', + 'vpci': '0000:05:00.1', + 'local_ip': '152.16.40.19', + 'type': 'PCI-PASSTHROUGH', + 'driver': "i40e", + 'netmask': '255.255.255.0', + 'dpdk_port_num': 1, + 'bandwidth': '10 Gbps', + 'dst_ip': '152.16.40.20', + 'local_iface_name': 'xe1', + 'local_mac': '00:00:00:00:00:01'}, 'vnfd-connection-point-ref': 'xe1', 'name': 'xe1'}]}], - 'description': 'Vpe approximation using DPDK', - 'mgmt-interface': - {'vdu-id': 'vpevnf-baremetal', - 'host': '1.1.1.1', - 'password': 'r00t', + 'description': 'Vpe approximation using DPDK', + 'mgmt-interface': + {'vdu-id': 'vpevnf-baremetal', + 'host': '1.1.1.1', + 'password': 'r00t', 'user': 'root', 'ip': '1.1.1.1'}, - 'benchmark': - {'kpi': ['packets_in', 'packets_fwd', 'packets_dropped']}, - 'connection-point': [{'type': 'VPORT', 'name': 'xe0'}, - {'type': 'VPORT', 'name': 'xe1'}], - 'id': 'VpeApproxVnf', 'name': 'VPEVnfSsh'}]}} + 'benchmark': + {'kpi': ['packets_in', 'packets_fwd', + 'packets_dropped']}, + 'connection-point': [{'type': 'VPORT', 'name': 'xe0'}, + {'type': 'VPORT', 'name': 'xe1'}], + 'id': 'VpeApproxVnf', 'name': 'VPEVnfSsh'}]}} TRAFFIC_PROFILE = { "schema": "isb:traffic_profile:0.1", @@ -135,7 +151,7 @@ class TestIXIATrafficGen(unittest.TestCase): "frame_size": 64}} TC_YAML = {'scenarios': [{'tc_options': - {'rfc2544': {'allowed_drop_rate': '0.8 - 1'}}, + {'rfc2544': {'allowed_drop_rate': '0.8 - 1'}}, 'runner': {'duration': 400, 'interval': 35, 'type': 'Duration'}, 'traffic_options': @@ -147,7 +163,8 @@ class TestIXIATrafficGen(unittest.TestCase): 'nodes': {'tg__1': 'trafficgen_1.yardstick', 'vnf__1': 'vnf.yardstick'}, 'topology': 'vpe_vnf_topology.yaml'}], - 'context': {'nfvi_type': 'baremetal', 'type': 'Node', + 'context': {'nfvi_type': 'baremetal', + 'type': contexts.CONTEXT_NODE, 'name': 'yardstick', 'file': '/etc/yardstick/nodes/pod.yaml'}, 'schema': 'yardstick:task:0.1'} @@ -160,7 +177,7 @@ class TestIXIATrafficGen(unittest.TestCase): ssh.from_node.return_value = ssh_mock vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] # NOTE(ralonsoh): check the object returned. - IxiaTrafficGen(NAME, vnfd) + tg_rfc2544_ixia.IxiaTrafficGen(NAME, vnfd, 'task_id') def test_listen_traffic(self, *args): with mock.patch("yardstick.ssh.SSH") as ssh: @@ -169,9 +186,11 @@ class TestIXIATrafficGen(unittest.TestCase): mock.Mock(return_value=(0, "", "")) ssh.from_node.return_value = ssh_mock vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - ixnet_traffic_gen = IxiaTrafficGen(NAME, vnfd) + ixnet_traffic_gen = tg_rfc2544_ixia.IxiaTrafficGen(NAME, vnfd, + 'task_id') self.assertIsNone(ixnet_traffic_gen.listen_traffic({})) + @mock.patch.object(ctx_base.Context, 'get_context_from_server', return_value='fake_context') def test_instantiate(self, *args): with mock.patch("yardstick.ssh.SSH") as ssh: ssh_mock = mock.Mock(autospec=ssh.SSH) @@ -181,19 +200,27 @@ class TestIXIATrafficGen(unittest.TestCase): mock.Mock(return_value=(0, "", "")) ssh.from_node.return_value = ssh_mock vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - ixnet_traffic_gen = IxiaTrafficGen(NAME, vnfd) + ixnet_traffic_gen = tg_rfc2544_ixia.IxiaTrafficGen(NAME, vnfd, + 'task_id') scenario_cfg = {'tc': "nsb_test_case", "topology": "", 'ixia_profile': "ixload.cfg"} - scenario_cfg.update({'options': {'packetsize': 64, - 'traffic_type': 4, - 'rfc2544': {'allowed_drop_rate': '0.8 - 1'}, - 'vnf__1': {'rules': 'acl_1rule.yaml', - 'vnf_config': {'lb_config': 'SW', - 'lb_count': 1, - 'worker_config': - '1C/1T', - 'worker_threads': 1}} - }}) + scenario_cfg.update( + { + 'options': { + 'packetsize': 64, + 'traffic_type': 4, + 'rfc2544': { + 'allowed_drop_rate': '0.8 - 1'}, + 'vnf__1': { + 'rules': 'acl_1rule.yaml', + 'vnf_config': { + 'lb_config': 'SW', + 'lb_count': 1, + 'worker_config': '1C/1T', + 'worker_threads': 1}}}}) + scenario_cfg.update({ + 'nodes': {ixnet_traffic_gen.name: "mock"} + }) ixnet_traffic_gen.topology = "" ixnet_traffic_gen.get_ixobj = mock.MagicMock() ixnet_traffic_gen._ixia_traffic_gen = mock.MagicMock() @@ -202,17 +229,27 @@ class TestIXIATrafficGen(unittest.TestCase): IOError, ixnet_traffic_gen.instantiate(scenario_cfg, {})) + @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', return_value='mock_node') def test_collect_kpi(self, *args): with mock.patch("yardstick.ssh.SSH") as ssh: ssh_mock = mock.Mock(autospec=ssh.SSH) ssh_mock.execute = \ mock.Mock(return_value=(0, "", "")) ssh.from_node.return_value = ssh_mock + vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - ixnet_traffic_gen = IxiaTrafficGen(NAME, vnfd) + ixnet_traffic_gen = tg_rfc2544_ixia.IxiaTrafficGen(NAME, vnfd, + 'task_id') + ixnet_traffic_gen.scenario_helper.scenario_cfg = { + 'nodes': {ixnet_traffic_gen.name: "mock"} + } ixnet_traffic_gen.data = {} restult = ixnet_traffic_gen.collect_kpi() - self.assertEqual({}, restult) + + expected = {'collect_stats': {}, + 'physical_node': 'mock_node'} + + self.assertEqual(expected, restult) def test_terminate(self, *args): with mock.patch("yardstick.ssh.SSH") as ssh: @@ -221,7 +258,8 @@ class TestIXIATrafficGen(unittest.TestCase): ssh_mock.execute = \ mock.Mock(return_value=(0, "", "")) ssh.from_node.return_value = ssh_mock - ixnet_traffic_gen = IxiaTrafficGen(NAME, vnfd) + ixnet_traffic_gen = tg_rfc2544_ixia.IxiaTrafficGen(NAME, vnfd, + 'task_id') ixnet_traffic_gen._terminated = mock.MagicMock() ixnet_traffic_gen._terminated.value = 0 ixnet_traffic_gen._ixia_traffic_gen = mock.MagicMock() @@ -237,13 +275,12 @@ class TestIXIATrafficGen(unittest.TestCase): def test__check_status(self, *args): vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - sut = IxiaTrafficGen('vnf1', vnfd) + sut = tg_rfc2544_ixia.IxiaTrafficGen('vnf1', vnfd, 'task_id') sut._check_status() - @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_rfc2544_ixia.time") @mock.patch("yardstick.ssh.SSH") def test_traffic_runner(self, mock_ssh, *args): - mock_traffic_profile = mock.Mock(autospec=TrafficProfile) + mock_traffic_profile = mock.Mock(autospec=tp_base.TrafficProfile) mock_traffic_profile.get_traffic_definition.return_value = "64" mock_traffic_profile.params = self.TRAFFIC_PROFILE # traffic_profile.ports is standardized on port_num @@ -299,10 +336,12 @@ class TestIXIATrafficGen(unittest.TestCase): }, ] - mock_traffic_profile.execute_traffic.return_value = ['Completed', samples] - mock_traffic_profile.get_drop_percentage.return_value = ['Completed', samples] + mock_traffic_profile.execute_traffic.return_value = [ + 'Completed', samples] + mock_traffic_profile.get_drop_percentage.return_value = [ + 'Completed', samples] - sut = IxiaTrafficGen(name, vnfd) + sut = tg_rfc2544_ixia.IxiaTrafficGen(name, vnfd, 'task_id') sut.vnf_port_pairs = [[[0], [1]]] sut.tc_file_name = self._get_file_abspath(TEST_FILE_YAML) sut.topology = "" @@ -346,7 +385,8 @@ class TestIXIATrafficGen(unittest.TestCase): mock.mock_open(), create=True) @mock.patch('yardstick.network_services.vnf_generic.vnf.tg_rfc2544_ixia.LOG.exception') def _traffic_runner(*args): - result = sut._traffic_runner(mock_traffic_profile) + sut._setup_mq_producer = mock.Mock(return_value='mq_producer') + result = sut._traffic_runner(mock_traffic_profile, mock.ANY) self.assertIsNone(result) _traffic_runner() diff --git a/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_trex.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_trex.py index b9a95a945..6aba41006 100644 --- a/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_trex.py +++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_trex.py @@ -11,45 +11,39 @@ # 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. -# - -from __future__ import absolute_import -import unittest import mock +import unittest -from tests.unit import STL_MOCKS -SSH_HELPER = 'yardstick.network_services.vnf_generic.vnf.sample_vnf.VnfSshHelper' - - -STLClient = mock.MagicMock() -stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) -stl_patch.start() - -if stl_patch: - from yardstick.network_services.vnf_generic.vnf.tg_rfc2544_trex import TrexTrafficGenRFC, \ - TrexRfcResourceHelper - from yardstick.network_services.vnf_generic.vnf import tg_rfc2544_trex - from yardstick.network_services.traffic_profile.base import TrafficProfile - from tests.unit.network_services.vnf_generic.vnf.test_base import FileAbsPath, mock_ssh - -MODULE_PATH = FileAbsPath(__file__) -get_file_abspath = MODULE_PATH.get_path +from yardstick.benchmark import contexts +from yardstick.benchmark.contexts import base as ctx_base +from yardstick.network_services.traffic_profile import base as tp_base +from yardstick.network_services.vnf_generic.vnf import sample_vnf +from yardstick.network_services.vnf_generic.vnf import tg_rfc2544_trex class TestTrexRfcResouceHelper(unittest.TestCase): - @mock.patch('yardstick.network_services.helpers.samplevnf_helper.MultiPortConfig') - @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_rfc2544_trex.time") - @mock.patch(SSH_HELPER) - def test__run_traffic_once(self, ssh, *_): - mock_ssh(ssh) + def test__run_traffic_once(self): + mock_setup_helper = mock.Mock() + mock_traffic_profile = mock.Mock() + mock_traffic_profile.config.duration = 3 + mock_traffic_profile.execute_traffic.return_value = ('fake_ports', + 'port_pg_id_map') + mock_traffic_profile.get_drop_percentage.return_value = 'percentage' + rfc_rh = tg_rfc2544_trex.TrexRfcResourceHelper(mock_setup_helper) + rfc_rh.TRANSIENT_PERIOD = 0 + rfc_rh.rfc2544_helper = mock.Mock() + + with mock.patch.object(rfc_rh, '_get_samples') as mock_get_samples: + rfc_rh._run_traffic_once(mock_traffic_profile) - mock_traffic_profile = mock.MagicMock(autospec=TrafficProfile, - **{'get_drop_percentage.return_value': {}}) - sut = TrexRfcResourceHelper(mock.MagicMock(), mock.MagicMock()) - sut.client = mock.MagicMock() - sut._run_traffic_once(mock_traffic_profile) + mock_traffic_profile.execute_traffic.assert_called_once_with(rfc_rh) + mock_traffic_profile.stop_traffic.assert_called_once_with(rfc_rh) + mock_traffic_profile.stop_traffic.assert_called_once() + mock_get_samples.assert_has_calls([ + mock.call('fake_ports', port_pg_id='port_pg_id_map'), + mock.call('fake_ports', port_pg_id='port_pg_id_map')]) class TestTrexTrafficGenRFC(unittest.TestCase): @@ -213,40 +207,47 @@ class TestTrexTrafficGenRFC(unittest.TestCase): ], 'context': { 'nfvi_type': 'baremetal', - 'type': 'Node', + 'type': contexts.CONTEXT_NODE, 'name': 'yardstick', 'file': '/etc/yardstick/nodes/pod.yaml', }, 'schema': 'yardstick:task:0.1', } - @mock.patch(SSH_HELPER) - def test___init__(self, ssh): - mock_ssh(ssh) - trex_traffic_gen = TrexTrafficGenRFC('vnf1', self.VNFD_0) - self.assertIsNotNone(trex_traffic_gen.resource_helper._terminated.value) + def setUp(self): + self._mock_ssh_helper = mock.patch.object(sample_vnf, 'VnfSshHelper') + self.mock_ssh_helper = self._mock_ssh_helper.start() + self.addCleanup(self._stop_mocks) - @mock.patch(SSH_HELPER) - def test_collect_kpi(self, ssh): - mock_ssh(ssh) - trex_traffic_gen = TrexTrafficGenRFC('vnf1', self.VNFD_0) - self.assertEqual(trex_traffic_gen.collect_kpi(), {}) + def _stop_mocks(self): + self._mock_ssh_helper.stop() - @mock.patch(SSH_HELPER) - def test_listen_traffic(self, ssh): - mock_ssh(ssh) - trex_traffic_gen = TrexTrafficGenRFC('vnf1', self.VNFD_0) - self.assertIsNone(trex_traffic_gen.listen_traffic({})) + def test___init__(self): + trex_traffic_gen = tg_rfc2544_trex.TrexTrafficGenRFC( + 'vnf1', self.VNFD_0, 'task_id') + self.assertIsNotNone(trex_traffic_gen.resource_helper._terminated.value) - @mock.patch(SSH_HELPER) - def test_instantiate(self, ssh): - mock_ssh(ssh) + @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', return_value='mock_node') + def test_collect_kpi(self, *args): + trex_traffic_gen = tg_rfc2544_trex.TrexTrafficGenRFC( + 'vnf1', self.VNFD_0, 'task_id') + trex_traffic_gen.scenario_helper.scenario_cfg = { + 'nodes': {trex_traffic_gen.name: "mock"} + } + expected = { + 'physical_node': 'mock_node', + 'collect_stats': {}, + } + self.assertEqual(trex_traffic_gen.collect_kpi(), expected) - mock_traffic_profile = mock.Mock(autospec=TrafficProfile) + @mock.patch.object(ctx_base.Context, 'get_context_from_server', return_value='fake_context') + def test_instantiate(self, *args): + mock_traffic_profile = mock.Mock(autospec=tp_base.TrafficProfile) mock_traffic_profile.get_traffic_definition.return_value = "64" mock_traffic_profile.params = self.TRAFFIC_PROFILE - trex_traffic_gen = TrexTrafficGenRFC('vnf1', self.VNFD_0) + trex_traffic_gen = tg_rfc2544_trex.TrexTrafficGenRFC( + 'vnf1', self.VNFD_0, 'task_id') trex_traffic_gen._start_server = mock.Mock(return_value=0) trex_traffic_gen.resource_helper = mock.MagicMock() trex_traffic_gen.setup_helper.setup_vnf_environment = mock.MagicMock() @@ -272,26 +273,25 @@ class TestTrexTrafficGenRFC(unittest.TestCase): }, } tg_rfc2544_trex.WAIT_TIME = 3 - scenario_cfg.update({"nodes": ["tg_1", "vnf_1"]}) + scenario_cfg.update({"nodes": {"tg_1": {}, "vnf1": {}}}) self.assertIsNone(trex_traffic_gen.instantiate(scenario_cfg, {})) - @mock.patch(SSH_HELPER) - def test_instantiate_error(self, ssh): - mock_ssh(ssh, exec_result=(1, "", "")) - - mock_traffic_profile = mock.Mock(autospec=TrafficProfile) + @mock.patch.object(ctx_base.Context, 'get_context_from_server', return_value='fake_context') + def test_instantiate_error(self, *args): + mock_traffic_profile = mock.Mock(autospec=tp_base.TrafficProfile) mock_traffic_profile.get_traffic_definition.return_value = "64" mock_traffic_profile.params = self.TRAFFIC_PROFILE - trex_traffic_gen = TrexTrafficGenRFC('vnf1', self.VNFD_0) + trex_traffic_gen = tg_rfc2544_trex.TrexTrafficGenRFC( + 'vnf1', self.VNFD_0, 'task_id') trex_traffic_gen.resource_helper = mock.MagicMock() trex_traffic_gen.setup_helper.setup_vnf_environment = mock.MagicMock() scenario_cfg = { "tc": "tc_baremetal_rfc2544_ipv4_1flow_64B", - "nodes": [ - "tg_1", - "vnf_1", - ], + "nodes": { + "tg_1": {}, + "vnf1": {} + }, "topology": 'nsb_test_case.yaml', 'options': { 'packetsize': 64, @@ -311,29 +311,3 @@ class TestTrexTrafficGenRFC(unittest.TestCase): }, } trex_traffic_gen.instantiate(scenario_cfg, {}) - - @mock.patch(SSH_HELPER) - def test__start_server(self, ssh): - mock_ssh(ssh) - trex_traffic_gen = TrexTrafficGenRFC('vnf1', self.VNFD_0) - trex_traffic_gen.resource_helper = mock.MagicMock() - self.assertIsNone(trex_traffic_gen._start_server()) - - @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_rfc2544_trex.time") - @mock.patch(SSH_HELPER) - def test__generate_trex_cfg(self, ssh, _): - mock_ssh(ssh) - - trex_traffic_gen = TrexTrafficGenRFC('vnf1', self.VNFD_0) - trex_traffic_gen.ssh_helper = mock.MagicMock() - trex_traffic_gen.resource_helper.ssh_helper = mock.MagicMock() - self.assertIsNone(trex_traffic_gen.resource_helper.generate_cfg()) - - def test_terminate(self): - with mock.patch(SSH_HELPER) as ssh: - ssh_mock = mock.Mock(autospec=ssh.SSH) - ssh_mock.execute = mock.Mock(return_value=(0, "", "")) - ssh.from_node.return_value = ssh_mock - trex_traffic_gen = TrexTrafficGenRFC('vnf1', self.VNFD_0) - trex_traffic_gen.resource_helper = mock.MagicMock() - self.assertIsNone(trex_traffic_gen.terminate()) diff --git a/tests/unit/network_services/vnf_generic/vnf/test_tg_trex.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_trex.py index f80d1f948..9ed2abbb9 100644 --- a/tests/unit/network_services/vnf_generic/vnf/test_tg_trex.py +++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_trex.py @@ -11,44 +11,37 @@ # 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. -# import copy -import mock +import mock import unittest -from tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh -from tests.unit import STL_MOCKS - - -SSH_HELPER = 'yardstick.network_services.vnf_generic.vnf.sample_vnf.VnfSshHelper' -NAME = 'vnf_1' +from yardstick.network_services.traffic_profile import base as tp_base +from yardstick.network_services.traffic_profile import rfc2544 +from yardstick.network_services.vnf_generic.vnf import sample_vnf +from yardstick.network_services.vnf_generic.vnf import tg_trex +from yardstick.benchmark.contexts import base as ctx_base -STLClient = mock.MagicMock() -stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) -stl_patch.start() -if stl_patch: - from yardstick.network_services.vnf_generic.vnf.tg_trex import \ - TrexTrafficGen, TrexResourceHelper - from yardstick.network_services.traffic_profile.base import TrafficProfile +NAME = 'vnf__1' class TestTrexTrafficGen(unittest.TestCase): + VNFD = {'vnfd:vnfd-catalog': - {'vnfd': - [{'short-name': 'VpeVnf', - 'vdu': - [{'routing_table': - [{'network': '152.16.100.20', - 'netmask': '255.255.255.0', - 'gateway': '152.16.100.20', - 'if': 'xe0'}, - {'network': '152.16.40.20', - 'netmask': '255.255.255.0', - 'gateway': '152.16.40.20', - 'if': 'xe1'}], + {'vnfd': + [{'short-name': 'VpeVnf', + 'vdu': + [{'routing_table': + [{'network': '152.16.100.20', + 'netmask': '255.255.255.0', + 'gateway': '152.16.100.20', + 'if': 'xe0'}, + {'network': '152.16.40.20', + 'netmask': '255.255.255.0', + 'gateway': '152.16.40.20', + 'if': 'xe1'}], 'description': 'VPE approximation using DPDK', 'name': 'vpevnf-baremetal', 'nd_route_tbl': @@ -63,49 +56,50 @@ class TestTrexTrafficGen(unittest.TestCase): 'id': 'vpevnf-baremetal', 'external-interface': [{'virtual-interface': - {'dst_mac': '00:00:00:00:00:04', - 'vpci': '0000:05:00.0', - 'local_ip': '152.16.100.19', - 'type': 'PCI-PASSTHROUGH', - 'netmask': '255.255.255.0', - 'dpdk_port_num': 0, - 'bandwidth': '10 Gbps', - 'driver': "i40e", - 'dst_ip': '152.16.100.20', - 'local_iface_name': 'xe0', - 'vld_id': 'downlink_0', - 'ifname': 'xe0', - 'local_mac': '00:00:00:00:00:02'}, + {'dst_mac': '00:00:00:00:00:04', + 'vpci': '0000:05:00.0', + 'local_ip': '152.16.100.19', + 'type': 'PCI-PASSTHROUGH', + 'netmask': '255.255.255.0', + 'dpdk_port_num': 0, + 'bandwidth': '10 Gbps', + 'driver': "i40e", + 'dst_ip': '152.16.100.20', + 'local_iface_name': 'xe0', + 'vld_id': 'downlink_0', + 'ifname': 'xe0', + 'local_mac': '00:00:00:00:00:02'}, 'vnfd-connection-point-ref': 'xe0', 'name': 'xe0'}, {'virtual-interface': - {'dst_mac': '00:00:00:00:00:03', - 'vpci': '0000:05:00.1', - 'local_ip': '152.16.40.19', - 'type': 'PCI-PASSTHROUGH', - 'driver': "i40e", - 'netmask': '255.255.255.0', - 'dpdk_port_num': 1, - 'bandwidth': '10 Gbps', - 'dst_ip': '152.16.40.20', - 'local_iface_name': 'xe1', - 'vld_id': 'uplink_0', - 'ifname': 'xe1', - 'local_mac': '00:00:00:00:00:01'}, + {'dst_mac': '00:00:00:00:00:03', + 'vpci': '0000:05:00.1', + 'local_ip': '152.16.40.19', + 'type': 'PCI-PASSTHROUGH', + 'driver': "i40e", + 'netmask': '255.255.255.0', + 'dpdk_port_num': 1, + 'bandwidth': '10 Gbps', + 'dst_ip': '152.16.40.20', + 'local_iface_name': 'xe1', + 'vld_id': 'uplink_0', + 'ifname': 'xe1', + 'local_mac': '00:00:00:00:00:01'}, 'vnfd-connection-point-ref': 'xe1', 'name': 'xe1'}]}], - 'description': 'Vpe approximation using DPDK', - 'mgmt-interface': - {'vdu-id': 'vpevnf-baremetal', - 'host': '1.1.1.1', - 'password': 'r00t', + 'description': 'Vpe approximation using DPDK', + 'mgmt-interface': + {'vdu-id': 'vpevnf-baremetal', + 'host': '1.1.1.1', + 'password': 'r00t', 'user': 'root', 'ip': '1.1.1.1'}, - 'benchmark': - {'kpi': ['packets_in', 'packets_fwd', 'packets_dropped']}, - 'connection-point': [{'type': 'VPORT', 'name': 'xe0'}, - {'type': 'VPORT', 'name': 'xe1'}], - 'id': 'VpeApproxVnf', 'name': 'VPEVnfSsh'}]}} + 'benchmark': + {'kpi': ['packets_in', 'packets_fwd', + 'packets_dropped']}, + 'connection-point': [{'type': 'VPORT', 'name': 'xe0'}, + {'type': 'VPORT', 'name': 'xe1'}], + 'id': 'VpeApproxVnf', 'name': 'VPEVnfSsh'}]}} TRAFFIC_PROFILE = { "schema": "isb:traffic_profile:0.1", @@ -167,7 +161,7 @@ class TestTrexTrafficGen(unittest.TestCase): "interfaces": { "xe0": { "local_iface_name": "ens786f0", - "vld_id": TrafficProfile.UPLINK, + "vld_id": tp_base.TrafficProfile.UPLINK, "netmask": "255.255.255.0", "vpci": "0000:05:00.0", "local_ip": "152.16.100.19", @@ -179,7 +173,7 @@ class TestTrexTrafficGen(unittest.TestCase): }, "xe1": { "local_iface_name": "ens786f1", - "vld_id": TrafficProfile.DOWNLINK, + "vld_id": tp_base.TrafficProfile.DOWNLINK, "netmask": "255.255.255.0", "vpci": "0000:05:00.1", "local_ip": "152.16.40.19", @@ -235,7 +229,7 @@ class TestTrexTrafficGen(unittest.TestCase): "interfaces": { "xe0": { "local_iface_name": "ens513f0", - "vld_id": TrafficProfile.DOWNLINK, + "vld_id": tp_base.TrafficProfile.DOWNLINK, "netmask": "255.255.255.0", "vpci": "0000:02:00.0", "local_ip": "152.16.40.20", @@ -269,7 +263,7 @@ class TestTrexTrafficGen(unittest.TestCase): "interfaces": { "xe0": { "local_iface_name": "ens785f0", - "vld_id": TrafficProfile.UPLINK, + "vld_id": tp_base.TrafficProfile.UPLINK, "netmask": "255.255.255.0", "vpci": "0000:05:00.0", "local_ip": "152.16.100.20", @@ -296,35 +290,44 @@ class TestTrexTrafficGen(unittest.TestCase): } } - @mock.patch(SSH_HELPER) - def test___init__(self, ssh): - mock_ssh(ssh) + def setUp(self): + self._mock_ssh_helper = mock.patch.object(sample_vnf, 'VnfSshHelper') + self.mock_ssh_helper = self._mock_ssh_helper.start() + self.addCleanup(self._stop_mocks) + + def _stop_mocks(self): + self._mock_ssh_helper.stop() + + def test___init__(self): vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - trex_traffic_gen = TrexTrafficGen(NAME, vnfd) - self.assertIsInstance(trex_traffic_gen.resource_helper, TrexResourceHelper) + trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd, 'task_id') + self.assertIsInstance(trex_traffic_gen.resource_helper, + tg_trex.TrexResourceHelper) - @mock.patch(SSH_HELPER) - def test_collect_kpi(self, ssh): - mock_ssh(ssh) + @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', return_value='mock_node') + def test_collect_kpi(self, *args): vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - trex_traffic_gen = TrexTrafficGen(NAME, vnfd) + trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd, 'task_id') + trex_traffic_gen.scenario_helper.scenario_cfg = { + 'nodes': {trex_traffic_gen.name: "mock"} + } trex_traffic_gen.resource_helper._queue.put({}) result = trex_traffic_gen.collect_kpi() - self.assertEqual({}, result) + expected = { + 'physical_node': 'mock_node', + 'collect_stats': {} + } + self.assertEqual(expected, result) - @mock.patch(SSH_HELPER) - def test_listen_traffic(self, ssh): - mock_ssh(ssh) + def test_listen_traffic(self): vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - trex_traffic_gen = TrexTrafficGen(NAME, vnfd) + trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd, 'task_id') self.assertIsNone(trex_traffic_gen.listen_traffic({})) - @mock.patch(SSH_HELPER) - def test_instantiate(self, ssh): - mock_ssh(ssh) - + @mock.patch.object(ctx_base.Context, 'get_context_from_server', return_value='fake_context') + def test_instantiate(self, *args): vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - trex_traffic_gen = TrexTrafficGen(NAME, vnfd) + trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd, 'task_id') trex_traffic_gen._start_server = mock.Mock(return_value=0) trex_traffic_gen._tg_process = mock.MagicMock() trex_traffic_gen._tg_process.start = mock.Mock() @@ -333,15 +336,13 @@ class TestTrexTrafficGen(unittest.TestCase): trex_traffic_gen.ssh_helper = mock.MagicMock() trex_traffic_gen.resource_helper.ssh_helper = mock.MagicMock() trex_traffic_gen.setup_helper.setup_vnf_environment = mock.MagicMock() + self.assertIsNone(trex_traffic_gen.instantiate(self.SCENARIO_CFG, + self.CONTEXT_CFG)) - self.assertIsNone(trex_traffic_gen.instantiate(self.SCENARIO_CFG, self.CONTEXT_CFG)) - - @mock.patch(SSH_HELPER) - def test_instantiate_error(self, ssh): - mock_ssh(ssh, exec_result=(1, "", "")) - + @mock.patch.object(ctx_base.Context, 'get_context_from_server', return_value='fake_context') + def test_instantiate_error(self, *args): vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - trex_traffic_gen = TrexTrafficGen(NAME, vnfd) + trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd, 'task_id') trex_traffic_gen._start_server = mock.Mock(return_value=0) trex_traffic_gen._tg_process = mock.MagicMock() trex_traffic_gen._tg_process.start = mock.Mock() @@ -349,135 +350,167 @@ class TestTrexTrafficGen(unittest.TestCase): trex_traffic_gen.ssh_helper = mock.MagicMock() trex_traffic_gen.resource_helper.ssh_helper = mock.MagicMock() trex_traffic_gen.setup_helper.setup_vnf_environment = mock.MagicMock() - self.assertIsNone(trex_traffic_gen.instantiate(self.SCENARIO_CFG, self.CONTEXT_CFG)) + self.assertIsNone(trex_traffic_gen.instantiate(self.SCENARIO_CFG, + self.CONTEXT_CFG)) - @mock.patch(SSH_HELPER) - def test__start_server(self, ssh): - mock_ssh(ssh) + def test__start_server(self): vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - trex_traffic_gen = TrexTrafficGen(NAME, vnfd) + trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd, 'task_id') trex_traffic_gen.ssh_helper = mock.MagicMock() trex_traffic_gen.resource_helper.ssh_helper = mock.MagicMock() trex_traffic_gen.scenario_helper.scenario_cfg = {} self.assertIsNone(trex_traffic_gen._start_server()) - @mock.patch(SSH_HELPER) - def test__start_server_multiple_queues(self, ssh): - mock_ssh(ssh) + def test__start_server_multiple_queues(self): vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - trex_traffic_gen = TrexTrafficGen(NAME, vnfd) + trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd, 'task_id') trex_traffic_gen.ssh_helper = mock.MagicMock() trex_traffic_gen.resource_helper.ssh_helper = mock.MagicMock() - trex_traffic_gen.scenario_helper.scenario_cfg = {"options": {NAME: {"queues_per_port": 2}}} + trex_traffic_gen.scenario_helper.scenario_cfg = { + "options": {NAME: {"queues_per_port": 2}}} self.assertIsNone(trex_traffic_gen._start_server()) - @mock.patch(SSH_HELPER) - def test__traffic_runner(self, ssh): - mock_ssh(ssh) - - mock_traffic_profile = mock.Mock(autospec=TrafficProfile) + def test__traffic_runner(self): + mock_traffic_profile = mock.Mock(autospec=tp_base.TrafficProfile) mock_traffic_profile.get_traffic_definition.return_value = "64" mock_traffic_profile.execute_traffic.return_value = "64" mock_traffic_profile.params = self.TRAFFIC_PROFILE vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - self.sut = TrexTrafficGen(NAME, vnfd) + self.sut = tg_trex.TrexTrafficGen(NAME, vnfd, 'task_id') self.sut.ssh_helper = mock.Mock() self.sut.ssh_helper.run = mock.Mock() - self.sut._connect_client = mock.Mock(autospec=STLClient) + self.sut._connect_client = mock.Mock() self.sut._connect_client.get_stats = mock.Mock(return_value="0") self.sut.resource_helper.RUN_DURATION = 0 self.sut.resource_helper.QUEUE_WAIT_TIME = 0 - # must generate cfg before we can run traffic so Trex port mapping is created + # must generate cfg before we can run traffic so Trex port mapping is + # created self.sut.resource_helper.generate_cfg() - self.sut._traffic_runner(mock_traffic_profile) + self.sut._setup_mq_producer = mock.Mock() + with mock.patch.object(self.sut.resource_helper, 'run_traffic'): + self.sut._traffic_runner(mock_traffic_profile, mock.ANY) - @mock.patch(SSH_HELPER) - def test__generate_trex_cfg(self, ssh): - mock_ssh(ssh) + def test__generate_trex_cfg(self): vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - trex_traffic_gen = TrexTrafficGen(NAME, vnfd) + trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd, 'task_id') trex_traffic_gen.resource_helper.ssh_helper = mock.MagicMock() self.assertIsNone(trex_traffic_gen.resource_helper.generate_cfg()) - @mock.patch(SSH_HELPER) - def test_build_ports_reversed_pci_ordering(self, ssh): - mock_ssh(ssh) + def test_build_ports_reversed_pci_ordering(self): vnfd = copy.deepcopy(self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]) vnfd['vdu'][0]['external-interface'] = [ {'virtual-interface': - {'dst_mac': '00:00:00:00:00:04', - 'vpci': '0000:05:00.0', - 'local_ip': '152.16.100.19', - 'type': 'PCI-PASSTHROUGH', - 'netmask': '255.255.255.0', - 'dpdk_port_num': 2, - 'bandwidth': '10 Gbps', - 'driver': "i40e", - 'dst_ip': '152.16.100.20', - 'local_iface_name': 'xe0', - 'vld_id': 'downlink_0', - 'ifname': 'xe0', - 'local_mac': '00:00:00:00:00:02'}, + {'dst_mac': '00:00:00:00:00:04', + 'vpci': '0000:05:00.0', + 'local_ip': '152.16.100.19', + 'type': 'PCI-PASSTHROUGH', + 'netmask': '255.255.255.0', + 'dpdk_port_num': 2, + 'bandwidth': '10 Gbps', + 'driver': "i40e", + 'dst_ip': '152.16.100.20', + 'local_iface_name': 'xe0', + 'vld_id': 'downlink_0', + 'ifname': 'xe0', + 'local_mac': '00:00:00:00:00:02'}, 'vnfd-connection-point-ref': 'xe0', 'name': 'xe0'}, {'virtual-interface': - {'dst_mac': '00:00:00:00:00:03', - 'vpci': '0000:04:00.0', - 'local_ip': '152.16.40.19', - 'type': 'PCI-PASSTHROUGH', - 'driver': "i40e", - 'netmask': '255.255.255.0', - 'dpdk_port_num': 0, - 'bandwidth': '10 Gbps', - 'dst_ip': '152.16.40.20', - 'local_iface_name': 'xe1', - 'vld_id': 'uplink_0', - 'ifname': 'xe1', - 'local_mac': '00:00:00:00:00:01'}, + {'dst_mac': '00:00:00:00:00:03', + 'vpci': '0000:04:00.0', + 'local_ip': '152.16.40.19', + 'type': 'PCI-PASSTHROUGH', + 'driver': "i40e", + 'netmask': '255.255.255.0', + 'dpdk_port_num': 0, + 'bandwidth': '10 Gbps', + 'dst_ip': '152.16.40.20', + 'local_iface_name': 'xe1', + 'vld_id': 'uplink_0', + 'ifname': 'xe1', + 'local_mac': '00:00:00:00:00:01'}, 'vnfd-connection-point-ref': 'xe1', 'name': 'xe1'}] - trex_traffic_gen = TrexTrafficGen(NAME, vnfd) + trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd, 'task_id') trex_traffic_gen.resource_helper.ssh_helper = mock.MagicMock() trex_traffic_gen.resource_helper.generate_cfg() trex_traffic_gen.resource_helper._build_ports() - self.assertEqual(sorted(trex_traffic_gen.resource_helper.all_ports), [0, 1]) + self.assertEqual(sorted(trex_traffic_gen.resource_helper.all_ports), + [0, 1]) # there is a gap in ordering - self.assertEqual(dict(trex_traffic_gen.resource_helper.dpdk_to_trex_port_map), - {0: 0, 2: 1}) - - @mock.patch(SSH_HELPER) - def test_run_traffic(self, ssh): - mock_ssh(ssh) + self.assertEqual( + {0: 0, 2: 1}, + dict(trex_traffic_gen.resource_helper.dpdk_to_trex_port_map)) - mock_traffic_profile = mock.Mock(autospec=TrafficProfile) + def test_run_traffic(self): + mock_traffic_profile = mock.Mock(autospec=tp_base.TrafficProfile) mock_traffic_profile.get_traffic_definition.return_value = "64" mock_traffic_profile.params = self.TRAFFIC_PROFILE vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - self.sut = TrexTrafficGen(NAME, vnfd) + self.sut = tg_trex.TrexTrafficGen(NAME, vnfd, 'task_id') self.sut.ssh_helper = mock.Mock() self.sut.ssh_helper.run = mock.Mock() self.sut._traffic_runner = mock.Mock(return_value=0) self.sut.resource_helper.client_started.value = 1 - result = self.sut.run_traffic(mock_traffic_profile) + self.sut.run_traffic(mock_traffic_profile) self.sut._traffic_process.terminate() - self.assertIsNotNone(result) - @mock.patch(SSH_HELPER) - def test_terminate(self, ssh): - mock_ssh(ssh) + def test_terminate(self): vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - trex_traffic_gen = TrexTrafficGen(NAME, vnfd) + trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd, 'task_id') trex_traffic_gen.ssh_helper = mock.MagicMock() trex_traffic_gen.resource_helper.ssh_helper = mock.MagicMock() self.assertIsNone(trex_traffic_gen.terminate()) - @mock.patch(SSH_HELPER) - def test__connect_client(self, ssh): - mock_ssh(ssh) + def test__connect_client(self): vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - trex_traffic_gen = TrexTrafficGen(NAME, vnfd) - client = mock.Mock(autospec=STLClient) + trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd, 'task_id') + client = mock.Mock() client.connect = mock.Mock(return_value=0) self.assertIsNotNone(trex_traffic_gen.resource_helper._connect(client)) + + +class TrexResourceHelperTestCase(unittest.TestCase): + + def test__get_samples(self): + mock_setup_helper = mock.Mock() + trex_rh = tg_trex.TrexResourceHelper(mock_setup_helper) + trex_rh.vnfd_helper.interfaces = [ + {'name': 'interface1'}, + {'name': 'interface2'}] + stats = { + 10: {'rx_pps': 5, 'ipackets': 200}, + 20: {'rx_pps': 10, 'ipackets': 300}, + 'latency': {1: {'latency': 'latency_port_10_pg_id_1'}, + 2: {'latency': 'latency_port_10_pg_id_2'}, + 3: {'latency': 'latency_port_20_pg_id_3'}, + 4: {'latency': 'latency_port_20_pg_id_4'}} + } + port_pg_id = rfc2544.PortPgIDMap() + port_pg_id.add_port(10) + port_pg_id.increase_pg_id() + port_pg_id.increase_pg_id() + port_pg_id.add_port(20) + port_pg_id.increase_pg_id() + port_pg_id.increase_pg_id() + + with mock.patch.object(trex_rh, 'get_stats') as mock_get_stats, \ + mock.patch.object(trex_rh.vnfd_helper, 'port_num') as \ + mock_port_num: + mock_get_stats.return_value = stats + mock_port_num.side_effect = [10, 20] + output = trex_rh._get_samples([10, 20], port_pg_id=port_pg_id) + + interface = output['interface1'] + self.assertEqual(5.0, interface['rx_throughput_fps']) + self.assertEqual(200, interface['in_packets']) + self.assertEqual('latency_port_10_pg_id_1', interface['latency'][1]) + self.assertEqual('latency_port_10_pg_id_2', interface['latency'][2]) + + interface = output['interface2'] + self.assertEqual(10.0, interface['rx_throughput_fps']) + self.assertEqual(300, interface['in_packets']) + self.assertEqual('latency_port_20_pg_id_3', interface['latency'][3]) + self.assertEqual('latency_port_20_pg_id_4', interface['latency'][4]) diff --git a/tests/unit/network_services/vnf_generic/vnf/test_udp_replay.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_udp_replay.py index 4cf4320f9..56c971da6 100644 --- a/tests/unit/network_services/vnf_generic/vnf/test_udp_replay.py +++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_udp_replay.py @@ -11,30 +11,21 @@ # 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. -# import unittest import mock import os -from tests.unit import STL_MOCKS -from tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh +from yardstick.tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh +from yardstick.benchmark.contexts import base as ctx_base +from yardstick.network_services.vnf_generic.vnf.udp_replay import UdpReplayApproxVnf +from yardstick.network_services.vnf_generic.vnf.sample_vnf import ScenarioHelper SSH_HELPER = 'yardstick.network_services.vnf_generic.vnf.sample_vnf.VnfSshHelper' -STLClient = mock.MagicMock() -stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) -stl_patch.start() - -if stl_patch: - from yardstick.network_services.vnf_generic.vnf.udp_replay import UdpReplayApproxVnf - from yardstick.network_services.vnf_generic.vnf.sample_vnf import ScenarioHelper - - TEST_FILE_YAML = 'nsb_test_case.yaml' - NAME = "vnf__1" @@ -326,34 +317,46 @@ class TestUdpReplayApproxVnf(unittest.TestCase): } def test___init__(self, *args): - udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0) + udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0, + 'task_id') self.assertIsNone(udp_replay_approx_vnf._vnf_process) @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.time") + @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', return_value='mock_node') @mock.patch(SSH_HELPER) def test_collect_kpi(self, ssh, *args): mock_ssh(ssh) vnfd = self.VNFD_0 - result = "stats\r\r\n\r\nUDP_Replay stats:\r\n--------------\r\n" \ - "Port\t\tRx Packet\t\tTx Packet\t\tRx Pkt Drop\t\tTx Pkt Drop \r\n"\ - "0\t\t7374156\t\t7374136\t\t\t0\t\t\t0\r\n" \ - "1\t\t7374316\t\t7374315\t\t\t0\t\t\t0\r\n\r\nReplay>\r\r\nReplay>" - udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, vnfd) + get_stats_ret_val = \ + "stats\r\r\n\r\nUDP_Replay stats:\r\n--------------\r\n" \ + "Port\t\tRx Packet\t\tTx Packet\t\tRx Pkt Drop\t\tTx Pkt Drop \r\n"\ + "0\t\t7374156\t\t7374136\t\t\t0\t\t\t0\r\n" \ + "1\t\t7374316\t\t7374315\t\t\t0\t\t\t0\r\n\r\nReplay>\r\r\nReplay>" + udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, vnfd, 'task_id') + udp_replay_approx_vnf.scenario_helper.scenario_cfg = { + 'nodes': {udp_replay_approx_vnf.name: "mock"} + } udp_replay_approx_vnf.q_in = mock.MagicMock() udp_replay_approx_vnf.q_out = mock.MagicMock() udp_replay_approx_vnf.q_out.qsize = mock.Mock(return_value=0) udp_replay_approx_vnf.all_ports = ["xe0", "xe1"] - udp_replay_approx_vnf.get_stats = mock.Mock(return_value=result) - result = {'collect_stats': {}, 'packets_dropped': 0, - 'packets_fwd': 14748451, 'packets_in': 14748472} + udp_replay_approx_vnf.get_stats = mock.Mock(return_value=get_stats_ret_val) + result = { + 'physical_node': 'mock_node', + 'collect_stats': {}, + 'packets_dropped': 0, + 'packets_fwd': 14748451, + 'packets_in': 14748472 + } self.assertEqual(result, udp_replay_approx_vnf.collect_kpi()) @mock.patch(SSH_HELPER) def test_get_stats(self, ssh, *args): mock_ssh(ssh) - udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0) + udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0, + 'task_id') udp_replay_approx_vnf.q_in = mock.MagicMock() udp_replay_approx_vnf.q_out = mock.MagicMock() udp_replay_approx_vnf.q_out.qsize = mock.Mock(return_value=0) @@ -370,14 +373,19 @@ class TestUdpReplayApproxVnf(unittest.TestCase): file_path = os.path.join(curr_path, filename) return file_path - @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.Context") + @mock.patch.object(ctx_base.Context, 'get_context_from_server') @mock.patch(SSH_HELPER) - def test__build_config(self, ssh, mock_context, *args): + def test__build_config(self, ssh, mock_get_ctx, *args): mock_ssh(ssh) - udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0) + nfvi_context = mock.Mock() + nfvi_context.attrs = {'nfvi_type': 'baremetal'} + mock_get_ctx.return_value = nfvi_context + + udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0, + 'task_id') udp_replay_approx_vnf.queue_wrapper = mock.MagicMock() - udp_replay_approx_vnf.nfvi_context = mock_context + udp_replay_approx_vnf.nfvi_context = mock_get_ctx udp_replay_approx_vnf.nfvi_context.attrs = {'nfvi_type': 'baremetal'} udp_replay_approx_vnf.setup_helper.bound_pci = [] udp_replay_approx_vnf.ssh_helper.provision_tool = mock.MagicMock(return_value="tool_path") @@ -391,13 +399,17 @@ class TestUdpReplayApproxVnf(unittest.TestCase): self.assertEqual(cmd_line, expected) @mock.patch('yardstick.network_services.vnf_generic.vnf.udp_replay.open') - @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.Context") + @mock.patch.object(ctx_base.Context, 'get_context_from_server') @mock.patch(SSH_HELPER) - def test__build_pipeline_kwargs(self, ssh, mock_context, *args): + def test__build_pipeline_kwargs(self, ssh, mock_get_ctx, *args): mock_ssh(ssh) - udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0) - udp_replay_approx_vnf.nfvi_context = mock_context - udp_replay_approx_vnf.nfvi_context.attrs = {'nfvi_type': 'baremetal'} + + nfvi_context = mock.Mock() + nfvi_context.attrs = {'nfvi_type': "baremetal"} + mock_get_ctx.return_value = nfvi_context + + udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0, + 'task_id') udp_replay_approx_vnf.setup_helper.bound_pci = ['0000:00:0.1', '0000:00:0.3'] udp_replay_approx_vnf.all_ports = ["xe0", "xe1"] udp_replay_approx_vnf.ssh_helper.provision_tool = mock.MagicMock(return_value="tool_path") @@ -419,7 +431,8 @@ class TestUdpReplayApproxVnf(unittest.TestCase): def test_run_udp_replay(self, ssh, *args): mock_ssh(ssh) - udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0) + udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0, + 'task_id') udp_replay_approx_vnf._build_config = mock.MagicMock() udp_replay_approx_vnf.queue_wrapper = mock.MagicMock() udp_replay_approx_vnf.scenario_helper = mock.MagicMock() @@ -428,12 +441,13 @@ class TestUdpReplayApproxVnf(unittest.TestCase): udp_replay_approx_vnf.ssh_helper.run.assert_called_once() - @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.Context") + @mock.patch.object(ctx_base.Context, 'get_context_from_server') @mock.patch(SSH_HELPER) def test_instantiate(self, ssh, *args): mock_ssh(ssh) - udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0) + udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0, + 'task_id') udp_replay_approx_vnf.q_out.put("Replay>") udp_replay_approx_vnf.WAIT_TIME = 0 udp_replay_approx_vnf.setup_helper.setup_vnf_environment = mock.Mock() @@ -447,11 +461,12 @@ class TestUdpReplayApproxVnf(unittest.TestCase): self.assertEqual(udp_replay_approx_vnf.wait_for_instantiate(), 0) - @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.Context") + @mock.patch.object(ctx_base.Context, 'get_context_from_server') @mock.patch('yardstick.ssh.SSH') @mock.patch(SSH_HELPER) def test_instantiate_panic(self, *args): - udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0) + udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0, + 'task_id') udp_replay_approx_vnf.WAIT_TIME = 0 udp_replay_approx_vnf.q_out.put("some text PANIC some text") udp_replay_approx_vnf.setup_helper.setup_vnf_environment = mock.Mock() diff --git a/tests/unit/network_services/vnf_generic/vnf/test_vfw_vnf.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_vfw_vnf.py index 48fc87ed4..efbb7a856 100644 --- a/tests/unit/network_services/vnf_generic/vnf/test_vfw_vnf.py +++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_vfw_vnf.py @@ -11,25 +11,17 @@ # 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. -# import unittest import mock import os -from tests.unit import STL_MOCKS -from tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh - from yardstick.common import utils - - -STLClient = mock.MagicMock() -stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) -stl_patch.start() - -if stl_patch: - from yardstick.network_services.vnf_generic.vnf.vfw_vnf import FWApproxVnf - from yardstick.network_services.nfvi.resource import ResourceProfile +from yardstick.benchmark.contexts import base as ctx_base +from yardstick.network_services.vnf_generic.vnf.vfw_vnf import FWApproxVnf +from yardstick.network_services.nfvi.resource import ResourceProfile +from yardstick.network_services.vnf_generic.vnf.vfw_vnf import FWApproxSetupEnvHelper +from yardstick.tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh TEST_FILE_YAML = 'nsb_test_case.yaml' @@ -240,7 +232,7 @@ class TestFWApproxVnf(unittest.TestCase): def test___init__(self, *args): vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - vfw_approx_vnf = FWApproxVnf(name, vnfd) + vfw_approx_vnf = FWApproxVnf(name, vnfd, 'task_id') self.assertIsNone(vfw_approx_vnf._vnf_process) STATS = """\ @@ -252,18 +244,21 @@ VFW TOTAL: pkts_received: 6007180, "pkts_fw_forwarded": 6007180, "pkts_drop_fw": "CT TOTAL: ct_packets_forwarded" : 6007180, " ct_packets_dropped" : 0, "ct_sessions" : {"active" : 130050, "open_attempt" : 130050, "re-open_attempt" : 0, "established" : 0, "closed" : 0, "timeout" : 0}, "ct_drops" : {"out_of_window" : 0, "invalid_conn" : 0, "invalid_state_transition" : 0 "RST" : 0} Action ID: 00, packetCount: 2954633, byteCount: 177277980 Action ID: 01, packetCount: 3052547, byteCount: 183152820 -pipeline> +pipeline> -pipeline> +pipeline> """ # noqa @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.time") + @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', return_value='mock_node') @mock.patch(SSH_HELPER) def test_collect_kpi(self, ssh, *args): mock_ssh(ssh) - vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - vfw_approx_vnf = FWApproxVnf(name, vnfd) + vfw_approx_vnf = FWApproxVnf(name, vnfd, 'task_id') + vfw_approx_vnf.scenario_helper.scenario_cfg = { + 'nodes': {vfw_approx_vnf.name: "mock"} + } vfw_approx_vnf.q_in = mock.MagicMock() vfw_approx_vnf.q_out = mock.MagicMock() vfw_approx_vnf.q_out.qsize = mock.Mock(return_value=0) @@ -272,6 +267,7 @@ pipeline> **{'collect_kpi.return_value': {"core": {}}}) vfw_approx_vnf.vnf_execute = mock.Mock(return_value=self.STATS) result = { + 'physical_node': 'mock_node', 'packets_dropped': 0, 'packets_fwd': 6007180, 'packets_in': 6007180, @@ -285,7 +281,7 @@ pipeline> mock_ssh(ssh) vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - vfw_approx_vnf = FWApproxVnf(name, vnfd) + vfw_approx_vnf = FWApproxVnf(name, vnfd, 'task_id') vfw_approx_vnf.q_in = mock.MagicMock() vfw_approx_vnf.q_out = mock.MagicMock() vfw_approx_vnf.q_out.qsize = mock.Mock(return_value=0) @@ -297,7 +293,7 @@ pipeline> mock_ssh(ssh) vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - vfw_approx_vnf = FWApproxVnf(name, vnfd) + vfw_approx_vnf = FWApproxVnf(name, vnfd, 'task_id') vfw_approx_vnf.q_in = mock.MagicMock() vfw_approx_vnf.q_out = mock.MagicMock() vfw_approx_vnf.q_out.qsize = mock.Mock(return_value=0) @@ -317,7 +313,7 @@ pipeline> mock_ssh(ssh) vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - vfw_approx_vnf = FWApproxVnf(name, vnfd) + vfw_approx_vnf = FWApproxVnf(name, vnfd, 'task_id') vfw_approx_vnf._build_config = mock.MagicMock() vfw_approx_vnf.queue_wrapper = mock.MagicMock() vfw_approx_vnf.ssh_helper = mock.MagicMock() @@ -333,14 +329,13 @@ pipeline> vfw_approx_vnf.ssh_helper.run.assert_called_once() @mock.patch.object(utils, 'find_relative_file') - @mock.patch("yardstick.network_services.vnf_generic.vnf.vfw_vnf.YangModel") - @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.Context") + @mock.patch.object(ctx_base.Context, 'get_context_from_server') @mock.patch(SSH_HELPER) def test_instantiate(self, ssh, *args): mock_ssh(ssh) vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - vfw_approx_vnf = FWApproxVnf(name, vnfd) + vfw_approx_vnf = FWApproxVnf(name, vnfd, 'task_id') vfw_approx_vnf.ssh_helper = ssh vfw_approx_vnf.deploy_helper = mock.MagicMock() vfw_approx_vnf.resource_helper = mock.MagicMock() @@ -349,3 +344,28 @@ pipeline> 'rules': ""}} self.scenario_cfg.update({"nodes": {"vnf__1": ""}}) self.assertIsNone(vfw_approx_vnf.instantiate(self.scenario_cfg, self.context_cfg)) + + +class TestFWApproxSetupEnvHelper(unittest.TestCase): + + @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.open') + @mock.patch.object(utils, 'find_relative_file') + @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.MultiPortConfig') + @mock.patch.object(utils, 'open_relative_file') + def test_build_config(self, *args): + vnfd_helper = mock.Mock() + ssh_helper = mock.Mock() + scenario_helper = mock.Mock() + scenario_helper.vnf_cfg = {'lb_config': 'HW'} + scenario_helper.options = {} + scenario_helper.all_options = {} + + vfw_approx_setup_helper = FWApproxSetupEnvHelper(vnfd_helper, ssh_helper, scenario_helper) + vfw_approx_setup_helper.get_flows_config = mock.Mock() + + vfw_approx_setup_helper.ssh_helper.provision_tool = mock.Mock(return_value='tool_path') + vfw_approx_setup_helper.ssh_helper.all_ports = mock.Mock() + vfw_approx_setup_helper.vnfd_helper.port_nums = mock.Mock(return_value=[0, 1]) + expected = 'sudo tool_path -p 0x3 -f /tmp/vfw_config -s /tmp/vfw_script --hwlb 3' + self.assertEqual(vfw_approx_setup_helper.build_config(), expected) + vfw_approx_setup_helper.get_flows_config.assert_called_once() diff --git a/tests/unit/network_services/vnf_generic/vnf/test_vpe_vnf.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_vpe_vnf.py index 8c45d973e..7b937dfb5 100644 --- a/tests/unit/network_services/vnf_generic/vnf/test_vpe_vnf.py +++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_vpe_vnf.py @@ -11,34 +11,20 @@ # 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. -# from multiprocessing import Process, Queue -import os import time import mock -import six.moves.configparser as configparser +from six.moves import configparser import unittest -from tests.unit import STL_MOCKS -from tests.unit.network_services.vnf_generic.vnf.test_base import FileAbsPath -from tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh -from yardstick.network_services.vnf_generic.vnf.base import QueueFileWrapper -from yardstick.network_services.vnf_generic.vnf.base import VnfdHelper - - -SSH_HELPER = 'yardstick.network_services.vnf_generic.vnf.sample_vnf.VnfSshHelper' - -STLClient = mock.MagicMock() -stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) -stl_patch.start() - -if stl_patch: - from yardstick.network_services.vnf_generic.vnf.vpe_vnf import ConfigCreate - from yardstick.network_services.nfvi.resource import ResourceProfile - from yardstick.network_services.vnf_generic.vnf.vpe_vnf import \ - VpeApproxVnf, VpeApproxSetupEnvHelper +from yardstick.benchmark.contexts import base as ctx_base +from yardstick.network_services.nfvi.resource import ResourceProfile +from yardstick.network_services.vnf_generic.vnf import base as vnf_base +from yardstick.network_services.vnf_generic.vnf import sample_vnf +from yardstick.network_services.vnf_generic.vnf import vpe_vnf +from yardstick.tests.unit.network_services.vnf_generic.vnf import test_base TEST_FILE_YAML = 'nsb_test_case.yaml' @@ -47,7 +33,7 @@ NAME = 'vnf_1' PING_OUTPUT_1 = "Pkts in: 101\r\n\tPkts dropped by AH: 100\r\n\tPkts dropped by other: 100" -MODULE_PATH = FileAbsPath(__file__) +MODULE_PATH = test_base.FileAbsPath(__file__) get_file_abspath = MODULE_PATH.get_path @@ -155,20 +141,20 @@ class TestConfigCreate(unittest.TestCase): } def test___init__(self): - vnfd_helper = VnfdHelper(self.VNFD_0) - config_create = ConfigCreate(vnfd_helper, 2) + vnfd_helper = vnf_base.VnfdHelper(self.VNFD_0) + config_create = vpe_vnf.ConfigCreate(vnfd_helper, 2) self.assertEqual(config_create.uplink_ports, ['xe0']) self.assertEqual(config_create.downlink_ports, ['xe1']) self.assertEqual(config_create.socket, 2) def test_dpdk_port_to_link_id(self): - vnfd_helper = VnfdHelper(self.VNFD_0) - config_create = ConfigCreate(vnfd_helper, 2) + vnfd_helper = vnf_base.VnfdHelper(self.VNFD_0) + config_create = vpe_vnf.ConfigCreate(vnfd_helper, 2) self.assertEqual(config_create.dpdk_port_to_link_id_map, {'xe0': 0, 'xe1': 1}) def test_vpe_initialize(self): - vnfd_helper = VnfdHelper(self.VNFD_0) - config_create = ConfigCreate(vnfd_helper, 2) + vnfd_helper = vnf_base.VnfdHelper(self.VNFD_0) + config_create = vpe_vnf.ConfigCreate(vnfd_helper, 2) config = configparser.ConfigParser() config_create.vpe_initialize(config) self.assertEqual(config.get('EAL', 'log_level'), '0') @@ -178,16 +164,16 @@ class TestConfigCreate(unittest.TestCase): self.assertEqual(config.get('MEMPOOL1', 'pool_size'), '2M') def test_vpe_rxq(self): - vnfd_helper = VnfdHelper(self.VNFD_0) - config_create = ConfigCreate(vnfd_helper, 2) + vnfd_helper = vnf_base.VnfdHelper(self.VNFD_0) + config_create = vpe_vnf.ConfigCreate(vnfd_helper, 2) config = configparser.ConfigParser() config_create.downlink_ports = ['xe0'] config_create.vpe_rxq(config) self.assertEqual(config.get('RXQ0.0', 'mempool'), 'MEMPOOL1') def test_get_sink_swq(self): - vnfd_helper = VnfdHelper(self.VNFD_0) - config_create = ConfigCreate(vnfd_helper, 2) + vnfd_helper = vnf_base.VnfdHelper(self.VNFD_0) + config_create = vpe_vnf.ConfigCreate(vnfd_helper, 2) config = configparser.ConfigParser() config.add_section('PIPELINE0') config.set('PIPELINE0', 'key1', 'value1') @@ -204,8 +190,8 @@ class TestConfigCreate(unittest.TestCase): self.assertEqual(config_create.get_sink_swq(config, 'PIPELINE0', 'key5', 5), 'SWQ0 SINK1') def test_generate_vpe_script(self): - vnfd_helper = VnfdHelper(self.VNFD_0) - vpe_config_vnf = ConfigCreate(vnfd_helper, 2) + vnfd_helper = vnf_base.VnfdHelper(self.VNFD_0) + vpe_config_vnf = vpe_vnf.ConfigCreate(vnfd_helper, 2) intf = [ { "name": 'xe1', @@ -229,15 +215,34 @@ class TestConfigCreate(unittest.TestCase): self.assertNotEqual(result, '') def test_create_vpe_config(self): - vnfd_helper = VnfdHelper(self.VNFD_0) - config_create = ConfigCreate(vnfd_helper, 23) - config_create.downlink_ports = ['xe1'] + vnfd_helper = vnf_base.VnfdHelper(self.VNFD_0) + config_create = vpe_vnf.ConfigCreate(vnfd_helper, 23) config_create.uplink_ports = ['xe1'] - curr_path = os.path.dirname(os.path.abspath(__file__)) - vpe_cfg = "samples/vnf_samples/nsut/vpe/vpe_config" - vnf_cfg = os.path.join(curr_path, "../../../../..", vpe_cfg) - config_create.create_vpe_config(vnf_cfg) - os.system("git checkout -- %s" % vnf_cfg) + with mock.patch.object(config_create, 'vpe_upstream') as mock_up, \ + mock.patch.object(config_create, 'vpe_downstream') as \ + mock_down, \ + mock.patch.object(config_create, 'vpe_tmq') as mock_tmq, \ + mock.patch.object(config_create, 'vpe_initialize') as \ + mock_ini, \ + mock.patch.object(config_create, 'vpe_rxq') as mock_rxq: + mock_ini_obj = mock.Mock() + mock_rxq_obj = mock.Mock() + mock_up_obj = mock.Mock() + mock_down_obj = mock.Mock() + mock_tmq_obj = mock.Mock() + mock_ini.return_value = mock_ini_obj + mock_rxq.return_value = mock_rxq_obj + mock_up.return_value = mock_up_obj + mock_down.return_value = mock_down_obj + mock_tmq.return_value = mock_tmq_obj + config_create.create_vpe_config('fake_config_file') + + mock_rxq.assert_called_once_with(mock_ini_obj) + mock_up.assert_called_once_with('fake_config_file', 0) + mock_down.assert_called_once_with('fake_config_file', 0) + mock_tmq.assert_called_once_with(mock_down_obj, 0) + mock_up_obj.write.assert_called_once() + mock_tmq_obj.write.assert_called_once() class TestVpeApproxVnf(unittest.TestCase): @@ -409,7 +414,7 @@ class TestVpeApproxVnf(unittest.TestCase): 'interfaces': { 'xe0': { 'local_iface_name': 'ens513f0', - 'vld_id': VpeApproxVnf.DOWNLINK, + 'vld_id': vpe_vnf.VpeApproxVnf.DOWNLINK, 'netmask': '255.255.255.0', 'local_ip': '152.16.40.20', 'dst_mac': '00:00:00:00:00:01', @@ -443,7 +448,7 @@ class TestVpeApproxVnf(unittest.TestCase): 'interfaces': { 'xe0': { 'local_iface_name': 'ens785f0', - 'vld_id': VpeApproxVnf.UPLINK, + 'vld_id': vpe_vnf.VpeApproxVnf.UPLINK, 'netmask': '255.255.255.0', 'local_ip': '152.16.100.20', 'dst_mac': '00:00:00:00:00:02', @@ -474,7 +479,7 @@ class TestVpeApproxVnf(unittest.TestCase): 'interfaces': { 'xe0': { 'local_iface_name': 'ens786f0', - 'vld_id': VpeApproxVnf.UPLINK, + 'vld_id': vpe_vnf.VpeApproxVnf.UPLINK, 'netmask': '255.255.255.0', 'local_ip': '152.16.100.19', 'dst_mac': '00:00:00:00:00:04', @@ -486,7 +491,7 @@ class TestVpeApproxVnf(unittest.TestCase): }, 'xe1': { 'local_iface_name': 'ens786f1', - 'vld_id': VpeApproxVnf.DOWNLINK, + 'vld_id': vpe_vnf.VpeApproxVnf.DOWNLINK, 'netmask': '255.255.255.0', 'local_ip': '152.16.40.19', 'dst_mac': '00:00:00:00:00:03', @@ -536,28 +541,39 @@ class TestVpeApproxVnf(unittest.TestCase): } def setUp(self): - self.mock_sleep = mock.patch.object(time, 'sleep').start() + self._mock_time_sleep = mock.patch.object(time, 'sleep') + self.mock_time_sleep = self._mock_time_sleep.start() + self.addCleanup(self._stop_mocks) + + def _stop_mocks(self): + self._mock_time_sleep.stop() def test___init__(self): - vpe_approx_vnf = VpeApproxVnf(NAME, self.VNFD_0) + vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0, 'task_id') self.assertIsNone(vpe_approx_vnf._vnf_process) - @mock.patch(SSH_HELPER) - def test_collect_kpi_sa_not_running(self, ssh): - mock_ssh(ssh) + @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', + return_value='mock_node') + @mock.patch.object(sample_vnf, 'VnfSshHelper') + def test_collect_kpi_sa_not_running(self, ssh, *args): + test_base.mock_ssh(ssh) resource = mock.Mock(autospec=ResourceProfile) resource.check_if_system_agent_running.return_value = 1, '' resource.amqp_collect_nfvi_kpi.return_value = {'foo': 234} resource.check_if_system_agent_running.return_value = (1, None) - vpe_approx_vnf = VpeApproxVnf(NAME, self.VNFD_0) + vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0, 'task_id') + vpe_approx_vnf.scenario_helper.scenario_cfg = { + 'nodes': {vpe_approx_vnf.name: "mock"} + } vpe_approx_vnf.q_in = mock.MagicMock() vpe_approx_vnf.q_out = mock.MagicMock() vpe_approx_vnf.q_out.qsize = mock.Mock(return_value=0) vpe_approx_vnf.resource_helper.resource = resource expected = { + 'physical_node': 'mock_node', 'pkt_in_down_stream': 0, 'pkt_in_up_stream': 0, 'pkt_drop_down_stream': 0, @@ -566,21 +582,27 @@ class TestVpeApproxVnf(unittest.TestCase): } self.assertEqual(vpe_approx_vnf.collect_kpi(), expected) - @mock.patch(SSH_HELPER) - def test_collect_kpi_sa_running(self, ssh): - mock_ssh(ssh) + @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', + return_value='mock_node') + @mock.patch.object(sample_vnf, 'VnfSshHelper') + def test_collect_kpi_sa_running(self, ssh, *args): + test_base.mock_ssh(ssh) resource = mock.Mock(autospec=ResourceProfile) resource.check_if_system_agent_running.return_value = 0, '1234' resource.amqp_collect_nfvi_kpi.return_value = {'foo': 234} - vpe_approx_vnf = VpeApproxVnf(NAME, self.VNFD_0) + vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0, 'task_id') + vpe_approx_vnf.scenario_helper.scenario_cfg = { + 'nodes': {vpe_approx_vnf.name: "mock"} + } vpe_approx_vnf.q_in = mock.MagicMock() vpe_approx_vnf.q_out = mock.MagicMock() vpe_approx_vnf.q_out.qsize = mock.Mock(return_value=0) vpe_approx_vnf.resource_helper.resource = resource expected = { + 'physical_node': 'mock_node', 'pkt_in_down_stream': 0, 'pkt_in_up_stream': 0, 'pkt_drop_down_stream': 0, @@ -589,20 +611,20 @@ class TestVpeApproxVnf(unittest.TestCase): } self.assertEqual(vpe_approx_vnf.collect_kpi(), expected) - @mock.patch(SSH_HELPER) + @mock.patch.object(sample_vnf, 'VnfSshHelper') def test_vnf_execute(self, ssh): - mock_ssh(ssh) - vpe_approx_vnf = VpeApproxVnf(NAME, self.VNFD_0) + test_base.mock_ssh(ssh) + vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0, 'task_id') vpe_approx_vnf.q_in = mock.MagicMock() vpe_approx_vnf.q_out = mock.MagicMock() vpe_approx_vnf.q_out.qsize = mock.Mock(return_value=0) self.assertEqual(vpe_approx_vnf.vnf_execute("quit", 0), '') - @mock.patch(SSH_HELPER) + @mock.patch.object(sample_vnf, 'VnfSshHelper') def test_run_vpe(self, ssh): - mock_ssh(ssh) + test_base.mock_ssh(ssh) - vpe_approx_vnf = VpeApproxVnf(NAME, self.VNFD_0) + vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0, 'task_id') vpe_approx_vnf.tc_file_name = get_file_abspath(TEST_FILE_YAML) vpe_approx_vnf.vnf_cfg = { 'lb_config': 'SW', @@ -629,14 +651,13 @@ class TestVpeApproxVnf(unittest.TestCase): self.assertIsNone(vpe_approx_vnf._run()) @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.MultiPortConfig") - @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.Context") @mock.patch("yardstick.network_services.vnf_generic.vnf.vpe_vnf.ConfigCreate") - @mock.patch("yardstick.network_services.vnf_generic.vnf.vpe_vnf.open") - @mock.patch(SSH_HELPER) + @mock.patch("six.moves.builtins.open") + @mock.patch.object(sample_vnf, 'VnfSshHelper') def test_build_config(self, ssh, *args): - mock_ssh(ssh) - vpe_approx_vnf = VpeApproxSetupEnvHelper(mock.MagicMock(), - mock.MagicMock(), mock.MagicMock()) + test_base.mock_ssh(ssh) + vpe_approx_vnf = vpe_vnf.VpeApproxSetupEnvHelper( + mock.MagicMock(), mock.MagicMock(), mock.MagicMock()) vpe_approx_vnf.tc_file_name = get_file_abspath(TEST_FILE_YAML) vpe_approx_vnf.generate_port_pairs = mock.Mock() vpe_approx_vnf.vnf_cfg = { @@ -663,11 +684,18 @@ class TestVpeApproxVnf(unittest.TestCase): vpe_approx_vnf.ssh_helper.bin_path = mock.Mock() vpe_approx_vnf.ssh_helper.upload_config_file = mock.MagicMock() self.assertIsNone(vpe_approx_vnf._build_vnf_ports()) - self.assertIsNotNone(vpe_approx_vnf.build_config()) - @mock.patch(SSH_HELPER) + vpe_approx_vnf.ssh_helper.provision_tool = mock.Mock(return_value='tool_path') + vpe_approx_vnf.ssh_helper.all_ports = mock.Mock() + vpe_approx_vnf.vnfd_helper.port_nums = mock.Mock(return_value=[0, 1]) + vpe_approx_vnf.scenario_helper.vnf_cfg = {'lb_config': 'HW'} + + expected = 'sudo tool_path -p 0x3 -f /tmp/vpe_config -s /tmp/vpe_script --hwlb 3' + self.assertEqual(vpe_approx_vnf.build_config(), expected) + + @mock.patch.object(sample_vnf, 'VnfSshHelper') def test_wait_for_instantiate(self, ssh): - mock_ssh(ssh) + test_base.mock_ssh(ssh) mock_process = mock.Mock(autospec=Process) mock_process.is_alive.return_value = True @@ -679,18 +707,19 @@ class TestVpeApproxVnf(unittest.TestCase): mock_resource = mock.MagicMock() - vpe_approx_vnf = VpeApproxVnf(NAME, self.VNFD_0) + vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0, 'task_id') vpe_approx_vnf._vnf_process = mock_process vpe_approx_vnf.q_out = mock_q_out - vpe_approx_vnf.queue_wrapper = mock.Mock(autospec=QueueFileWrapper) + vpe_approx_vnf.queue_wrapper = mock.Mock( + autospec=vnf_base.QueueFileWrapper) vpe_approx_vnf.resource_helper.resource = mock_resource vpe_approx_vnf.q_out.put("pipeline>") self.assertEqual(vpe_approx_vnf.wait_for_instantiate(), 432) - @mock.patch(SSH_HELPER) + @mock.patch.object(sample_vnf, 'VnfSshHelper') def test_wait_for_instantiate_fragmented(self, ssh): - mock_ssh(ssh) + test_base.mock_ssh(ssh) mock_process = mock.Mock(autospec=Process) mock_process.is_alive.return_value = True @@ -703,17 +732,18 @@ class TestVpeApproxVnf(unittest.TestCase): mock_resource = mock.MagicMock() - vpe_approx_vnf = VpeApproxVnf(NAME, self.VNFD_0) + vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0, 'task_id') vpe_approx_vnf._vnf_process = mock_process vpe_approx_vnf.q_out = mock_q_out - vpe_approx_vnf.queue_wrapper = mock.Mock(autospec=QueueFileWrapper) + vpe_approx_vnf.queue_wrapper = mock.Mock( + autospec=vnf_base.QueueFileWrapper) vpe_approx_vnf.resource_helper.resource = mock_resource self.assertEqual(vpe_approx_vnf.wait_for_instantiate(), 432) - @mock.patch(SSH_HELPER) + @mock.patch.object(sample_vnf, 'VnfSshHelper') def test_wait_for_instantiate_crash(self, ssh): - mock_ssh(ssh, exec_result=(1, "", "")) + test_base.mock_ssh(ssh, exec_result=(1, "", "")) mock_process = mock.Mock(autospec=Process) mock_process.is_alive.return_value = False @@ -721,7 +751,7 @@ class TestVpeApproxVnf(unittest.TestCase): mock_resource = mock.MagicMock() - vpe_approx_vnf = VpeApproxVnf(NAME, self.VNFD_0) + vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0, 'task_id') vpe_approx_vnf._vnf_process = mock_process vpe_approx_vnf.resource_helper.resource = mock_resource @@ -730,9 +760,9 @@ class TestVpeApproxVnf(unittest.TestCase): self.assertIn('VNF process died', str(raised.exception)) - @mock.patch(SSH_HELPER) + @mock.patch.object(sample_vnf, 'VnfSshHelper') def test_wait_for_instantiate_panic(self, ssh): - mock_ssh(ssh, exec_result=(1, "", "")) + test_base.mock_ssh(ssh, exec_result=(1, "", "")) mock_process = mock.Mock(autospec=Process) mock_process.is_alive.return_value = True @@ -740,7 +770,7 @@ class TestVpeApproxVnf(unittest.TestCase): mock_resource = mock.MagicMock() - vpe_approx_vnf = VpeApproxVnf(NAME, self.VNFD_0) + vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0, 'task_id') vpe_approx_vnf._vnf_process = mock_process vpe_approx_vnf.resource_helper.resource = mock_resource @@ -750,9 +780,9 @@ class TestVpeApproxVnf(unittest.TestCase): self.assertIn('Error starting', str(raised.exception)) - @mock.patch(SSH_HELPER) + @mock.patch.object(sample_vnf, 'VnfSshHelper') def test_wait_for_instantiate_panic_fragmented(self, ssh): - mock_ssh(ssh, exec_result=(1, "", "")) + test_base.mock_ssh(ssh, exec_result=(1, "", "")) mock_process = mock.Mock(autospec=Process) mock_process.is_alive.return_value = True @@ -765,7 +795,7 @@ class TestVpeApproxVnf(unittest.TestCase): mock_resource = mock.MagicMock() - vpe_approx_vnf = VpeApproxVnf(NAME, self.VNFD_0) + vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0, 'task_id') vpe_approx_vnf._vnf_process = mock_process vpe_approx_vnf.q_out = mock_q_out vpe_approx_vnf.resource_helper.resource = mock_resource @@ -775,11 +805,11 @@ class TestVpeApproxVnf(unittest.TestCase): self.assertIn('Error starting', str(raised.exception)) - @mock.patch(SSH_HELPER) + @mock.patch.object(sample_vnf, 'VnfSshHelper') def test_terminate(self, ssh): - mock_ssh(ssh) + test_base.mock_ssh(ssh) - vpe_approx_vnf = VpeApproxVnf(NAME, self.VNFD_0) + vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0, 'task_id') vpe_approx_vnf._vnf_process = mock.MagicMock() vpe_approx_vnf._resource_collect_stop = mock.Mock() vpe_approx_vnf.resource_helper = mock.MagicMock() diff --git a/yardstick/tests/unit/orchestrator/test_kubernetes.py b/yardstick/tests/unit/orchestrator/test_kubernetes.py index f2bc5b0f4..2d5c4a26f 100644 --- a/yardstick/tests/unit/orchestrator/test_kubernetes.py +++ b/yardstick/tests/unit/orchestrator/test_kubernetes.py @@ -7,15 +7,17 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -# Unittest for yardstick.benchmark.orchestrator.heat -import unittest +import copy + import mock -from yardstick.orchestrator.kubernetes import KubernetesObject -from yardstick.orchestrator.kubernetes import KubernetesTemplate +from yardstick.common import exceptions +from yardstick.common import kubernetes_utils +from yardstick.orchestrator import kubernetes +from yardstick.tests.unit import base -class GetTemplateTestCase(unittest.TestCase): +class GetTemplateTestCase(base.BaseUnitTestCase): def test_get_template(self): output_t = { @@ -47,8 +49,9 @@ service ssh restart;while true ; do sleep 10000; done" "name": "host-k8s-86096c30-container", "volumeMounts": [ { - "mountPath": "/root/.ssh/", - "name": "k8s-86096c30-key" + "mountPath": "/tmp/.ssh/", + "name": "k8s-86096c30-key", + "readOnly": False } ] } @@ -63,7 +66,11 @@ service ssh restart;while true ; do sleep 10000; done" ], "nodeSelector": { "kubernetes.io/hostname": "node-01" - } + }, + "restartPolicy": "Always", + "tolerations": [ + {"operator": "Exists"} + ] } } } @@ -73,14 +80,24 @@ service ssh restart;while true ; do sleep 10000; done" 'args': ['-c', 'chmod 700 ~/.ssh; chmod 600 ~/.ssh/*; \ service ssh restart;while true ; do sleep 10000; done'], 'ssh_key': 'k8s-86096c30-key', - 'nodeSelector': {'kubernetes.io/hostname': 'node-01'} + 'nodeSelector': {'kubernetes.io/hostname': 'node-01'}, + 'volumes': [], + 'restartPolicy': 'Always' } name = 'host-k8s-86096c30' - output_r = KubernetesObject(name, **input_s).get_template() + output_r = kubernetes.ReplicationControllerObject( + name, **input_s).get_template() self.assertEqual(output_r, output_t) + def test_get_template_invalid_restart_policy(self): + input_s = {'restartPolicy': 'invalid_option'} + name = 'host-k8s-86096c30' + with self.assertRaises(exceptions.KubernetesWrongRestartPolicy): + kubernetes.ReplicationControllerObject( + name, **input_s).get_template() -class GetRcPodsTestCase(unittest.TestCase): + +class GetRcPodsTestCase(base.BaseUnitTestCase): @mock.patch('yardstick.orchestrator.kubernetes.k8s_utils.get_pod_list') def test_get_rc_pods(self, mock_get_pod_list): @@ -98,7 +115,529 @@ service ssh restart;while true ; do sleep 10000; done'] service ssh restart;while true ; do sleep 10000; done'] } } - k8s_template = KubernetesTemplate('k8s-86096c30', servers) + k8s_template = kubernetes.KubernetesTemplate('k8s-86096c30', servers) mock_get_pod_list.return_value.items = [] pods = k8s_template.get_rc_pods() self.assertEqual(pods, []) + + +class ReplicationControllerObjectTestCase(base.BaseUnitTestCase): + + def test__init_one_container(self): + pod_name = 'pod_name' + _kwargs = {'args': ['arg1', 'arg2'], + 'image': 'fake_image', + 'command': 'fake_command'} + k8s_obj = kubernetes.ReplicationControllerObject(pod_name, **_kwargs) + self.assertEqual(1, len(k8s_obj._containers)) + container = k8s_obj._containers[0] + self.assertEqual(['arg1', 'arg2'], container._args) + self.assertEqual('fake_image', container._image) + self.assertEqual(['fake_command'], container._command) + self.assertEqual([], container._volume_mounts) + + def test__init_multipe_containers(self): + pod_name = 'pod_name' + containers = [] + for i in range(5): + containers.append({'args': ['arg1', 'arg2'], + 'image': 'fake_image_%s' % i, + 'command': 'fake_command_%s' % i}) + _kwargs = {'containers': containers} + k8s_obj = kubernetes.ReplicationControllerObject(pod_name, **_kwargs) + self.assertEqual(5, len(k8s_obj._containers)) + for i in range(5): + container = k8s_obj._containers[i] + self.assertEqual(['arg1', 'arg2'], container._args) + self.assertEqual('fake_image_%s' % i, container._image) + self.assertEqual(['fake_command_%s' % i], container._command) + self.assertEqual([], container._volume_mounts) + + def test__add_volumes(self): + volume1 = {'name': 'fake_sshkey', + 'configMap': {'name': 'fake_sshkey'}} + volume2 = {'name': 'volume2', + 'configMap': 'data'} + k8s_obj = kubernetes.ReplicationControllerObject( + 'name', ssh_key='fake_sshkey', volumes=[volume2]) + k8s_obj._add_volumes() + volumes = k8s_obj.template['spec']['template']['spec']['volumes'] + self.assertEqual(sorted([volume1, volume2], key=lambda k: k['name']), + sorted(volumes, key=lambda k: k['name'])) + + def test__add_volumes_no_volumes(self): + volume1 = {'name': 'fake_sshkey', + 'configMap': {'name': 'fake_sshkey'}} + k8s_obj = kubernetes.ReplicationControllerObject( + 'name', ssh_key='fake_sshkey') + k8s_obj._add_volumes() + volumes = k8s_obj.template['spec']['template']['spec']['volumes'] + self.assertEqual([volume1], volumes) + + def test__create_ssh_key_volume(self): + expected = {'name': 'fake_sshkey', + 'configMap': {'name': 'fake_sshkey'}} + k8s_obj = kubernetes.ReplicationControllerObject( + 'name', ssh_key='fake_sshkey') + self.assertEqual(expected, k8s_obj._create_ssh_key_volume()) + + def test__create_volume_item(self): + for vol_type in kubernetes_utils.get_volume_types(): + volume = {'name': 'vol_name', + vol_type: 'data'} + self.assertEqual( + volume, + kubernetes.ReplicationControllerObject. + _create_volume_item(volume)) + + def test__create_volume_item_invalid_type(self): + volume = {'name': 'vol_name', + 'invalid_type': 'data'} + with self.assertRaises(exceptions.KubernetesTemplateInvalidVolumeType): + kubernetes.ReplicationControllerObject._create_volume_item(volume) + + def test__add_security_context(self): + k8s_obj = kubernetes.ReplicationControllerObject('pod_name') + self.assertNotIn('securityContext', + k8s_obj.template['spec']['template']['spec']) + + k8s_obj._security_context = {'key_pod': 'value_pod'} + k8s_obj._add_security_context() + self.assertEqual( + {'key_pod': 'value_pod'}, + k8s_obj.template['spec']['template']['spec']['securityContext']) + + def test__add_security_context_by_init(self): + containers = [] + for i in range(5): + containers.append( + {'securityContext': {'key%s' % i: 'value%s' % i}}) + _kwargs = {'containers': containers, + 'securityContext': {'key_pod': 'value_pod'}} + k8s_obj = kubernetes.ReplicationControllerObject('pod_name', **_kwargs) + self.assertEqual( + {'key_pod': 'value_pod'}, + k8s_obj.template['spec']['template']['spec']['securityContext']) + for i in range(5): + container = ( + k8s_obj.template['spec']['template']['spec']['containers'][i]) + self.assertEqual({'key%s' % i: 'value%s' % i}, + container['securityContext']) + + def test__add_networks(self): + k8s_obj = kubernetes.ReplicationControllerObject( + 'name', networks=['network1', 'network2', 'network3']) + k8s_obj._add_networks() + networks = k8s_obj.\ + template['spec']['template']['metadata']['annotations']['networks'] + expected = ('[{"name": "network1"}, {"name": "network2"}, ' + '{"name": "network3"}]') + self.assertEqual(expected, networks) + + def test__add_tolerations(self): + _kwargs = {'tolerations': [{'key': 'key1', + 'value': 'value2', + 'effect': 'effect3', + 'operator': 'operator4', + 'wrong_key': 'error_key'}] + } + k8s_obj = kubernetes.ReplicationControllerObject('pod_name', **_kwargs) + k8s_obj._add_tolerations() + _tol = k8s_obj.template['spec']['template']['spec']['tolerations'] + self.assertEqual(1, len(_tol)) + self.assertEqual({'key': 'key1', + 'value': 'value2', + 'effect': 'effect3', + 'operator': 'operator4'}, + _tol[0]) + + def test__add_tolerations_default(self): + k8s_obj = kubernetes.ReplicationControllerObject('pod_name') + k8s_obj._add_tolerations() + _tol = k8s_obj.template['spec']['template']['spec']['tolerations'] + self.assertEqual(1, len(_tol)) + self.assertEqual({'operator': 'Exists'}, _tol[0]) + + +class ContainerObjectTestCase(base.BaseUnitTestCase): + + def test__create_volume_mounts(self): + volume_mount = {'name': 'fake_name', + 'mountPath': 'fake_path'} + ssh_vol = {'name': 'fake_ssh_key', + 'mountPath': kubernetes.ContainerObject.SSH_MOUNT_PATH, + 'readOnly': False} + expected = copy.deepcopy(volume_mount) + expected['readOnly'] = False + expected = [expected, ssh_vol] + container_obj = kubernetes.ContainerObject( + 'cname', 'fake_ssh_key', volumeMounts=[volume_mount]) + output = container_obj._create_volume_mounts() + self.assertEqual(expected, output) + + def test__create_volume_mounts_no_volume_mounts(self): + ssh_vol = {'name': 'fake_ssh_key2', + 'mountPath': kubernetes.ContainerObject.SSH_MOUNT_PATH, + 'readOnly': False} + container_obj = kubernetes.ContainerObject('name', 'fake_ssh_key2') + output = container_obj._create_volume_mounts() + self.assertEqual([ssh_vol], output) + + def test__create_volume_mounts_item(self): + volume_mount = {'name': 'fake_name', + 'mountPath': 'fake_path'} + expected = copy.deepcopy(volume_mount) + expected['readOnly'] = False + output = kubernetes.ContainerObject._create_volume_mounts_item( + volume_mount) + self.assertEqual(expected, output) + + def test_get_container_item(self): + volume_mount = {'name': 'fake_name', + 'mountPath': 'fake_path'} + args = ['arg1', 'arg2'] + container_obj = kubernetes.ContainerObject( + 'cname', ssh_key='fake_sshkey', volumeMount=[volume_mount], + args=args) + expected = {'args': args, + 'command': kubernetes.ContainerObject.COMMAND_DEFAULT, + 'image': kubernetes.ContainerObject.IMAGE_DEFAULT, + 'name': 'cname-container', + 'volumeMounts': container_obj._create_volume_mounts()} + self.assertEqual(expected, container_obj.get_container_item()) + + def test_get_container_item_with_security_context(self): + volume_mount = {'name': 'fake_name', + 'mountPath': 'fake_path'} + args = ['arg1', 'arg2'] + container_obj = kubernetes.ContainerObject( + 'cname', ssh_key='fake_sshkey', volumeMount=[volume_mount], + args=args, securityContext={'key': 'value'}) + expected = {'args': args, + 'command': kubernetes.ContainerObject.COMMAND_DEFAULT, + 'image': kubernetes.ContainerObject.IMAGE_DEFAULT, + 'name': 'cname-container', + 'volumeMounts': container_obj._create_volume_mounts(), + 'securityContext': {'key': 'value'}} + self.assertEqual(expected, container_obj.get_container_item()) + + def test_get_container_item_with_env(self): + volume_mount = {'name': 'fake_name', + 'mountPath': 'fake_path'} + args = ['arg1', 'arg2'] + container_obj = kubernetes.ContainerObject( + 'cname', ssh_key='fake_sshkey', volumeMount=[volume_mount], + args=args, env=[{'name': 'fake_var_name', + 'value': 'fake_var_value'}]) + expected = {'args': args, + 'command': kubernetes.ContainerObject.COMMAND_DEFAULT, + 'image': kubernetes.ContainerObject.IMAGE_DEFAULT, + 'name': 'cname-container', + 'volumeMounts': container_obj._create_volume_mounts(), + 'env': [{'name': 'fake_var_name', + 'value': 'fake_var_value'}]} + self.assertEqual(expected, container_obj.get_container_item()) + + def test_get_container_item_with_ports_multi_parameter(self): + volume_mount = {'name': 'fake_name', + 'mountPath': 'fake_path'} + args = ['arg1', 'arg2'] + container_obj = kubernetes.ContainerObject( + 'cname', ssh_key='fake_sshkey', volumeMount=[volume_mount], + args=args, ports=[{'containerPort': 'fake_port_name', + 'hostPort': 'fake_host_port', + 'name': 'fake_name', + 'protocol': 'fake_protocol', + 'invalid_varible': 'fakeinvalid_varible', + 'hostIP': 'fake_port_number'}]) + expected = {'args': args, + 'command': kubernetes.ContainerObject.COMMAND_DEFAULT, + 'image': kubernetes.ContainerObject.IMAGE_DEFAULT, + 'name': 'cname-container', + 'volumeMounts': container_obj._create_volume_mounts(), + 'ports': [{'containerPort': 'fake_port_name', + 'hostPort': 'fake_host_port', + 'name': 'fake_name', + 'protocol': 'fake_protocol', + 'hostIP': 'fake_port_number'}]} + self.assertEqual(expected, container_obj.get_container_item()) + + def test_get_container_item_with_ports_no_container_port(self): + with self.assertRaises(exceptions.KubernetesContainerPortNotDefined): + volume_mount = {'name': 'fake_name', + 'mountPath': 'fake_path'} + args = ['arg1', 'arg2'] + container_obj = kubernetes.ContainerObject( + 'cname', ssh_key='fake_sshkey', volumeMount=[volume_mount], + args=args, ports=[{'hostPort': 'fake_host_port', + 'name': 'fake_name', + 'protocol': 'fake_protocol', + 'hostIP': 'fake_port_number'}]) + container_obj.get_container_item() + + def test_get_container_item_with_resources(self): + volume_mount = {'name': 'fake_name', + 'mountPath': 'fake_path'} + args = ['arg1', 'arg2'] + resources = {'requests': {'key1': 'val1'}, + 'limits': {'key2': 'val2'}, + 'other_key': {'key3': 'val3'}} + container_obj = kubernetes.ContainerObject( + 'cname', ssh_key='fake_sshkey', volumeMount=[volume_mount], + args=args, resources=resources) + expected = {'args': args, + 'command': kubernetes.ContainerObject.COMMAND_DEFAULT, + 'image': kubernetes.ContainerObject.IMAGE_DEFAULT, + 'name': 'cname-container', + 'volumeMounts': container_obj._create_volume_mounts(), + 'resources': {'requests': {'key1': 'val1'}, + 'limits': {'key2': 'val2'}}} + self.assertEqual(expected, container_obj.get_container_item()) + + def test_get_container_item_image_pull_policy(self): + container_obj = kubernetes.ContainerObject( + 'cname', ssh_key='fake_sshkey', imagePullPolicy='Always') + expected = {'args': [], + 'command': kubernetes.ContainerObject.COMMAND_DEFAULT, + 'image': kubernetes.ContainerObject.IMAGE_DEFAULT, + 'name': 'cname-container', + 'volumeMounts': container_obj._create_volume_mounts(), + 'imagePullPolicy':'Always'} + self.assertEqual(expected, container_obj.get_container_item()) + + def test_get_container_item_with_tty_stdin(self): + args = ['arg1', 'arg2'] + container_obj = kubernetes.ContainerObject( + 'cname', 'fake_sshkey', args=args, tty=False, stdin=True) + expected = {'args': args, + 'command': kubernetes.ContainerObject.COMMAND_DEFAULT, + 'image': kubernetes.ContainerObject.IMAGE_DEFAULT, + 'name': 'cname-container', + 'volumeMounts': container_obj._create_volume_mounts(), + 'tty': False, + 'stdin': True} + self.assertEqual(expected, container_obj.get_container_item()) + + def test__parse_commands_string(self): + container_obj = kubernetes.ContainerObject('cname', 'fake_sshkey') + self.assertEqual(['fake command'], + container_obj._parse_commands('fake command')) + + def test__parse_commands_list(self): + container_obj = kubernetes.ContainerObject('cname', 'fake_sshkey') + self.assertEqual(['cmd1', 'cmd2'], + container_obj._parse_commands(['cmd1', 'cmd2'])) + + def test__parse_commands_exception(self): + container_obj = kubernetes.ContainerObject('cname', 'fake_sshkey') + with self.assertRaises(exceptions.KubernetesContainerCommandType): + container_obj._parse_commands({}) + + +class CustomResourceDefinitionObjectTestCase(base.BaseUnitTestCase): + + def test__init(self): + template = { + 'metadata': { + 'name': 'newcrds.ctx_name.com' + }, + 'spec': { + 'group': 'ctx_name.com', + 'version': 'v2', + 'scope': 'scope', + 'names': {'plural': 'newcrds', + 'singular': 'newcrd', + 'kind': 'Newcrd'} + } + } + crd_obj = kubernetes.CustomResourceDefinitionObject( + 'ctx_name', name='newcrd', version='v2', scope='scope') + self.assertEqual('newcrds.ctx_name.com', crd_obj._name) + self.assertEqual(template, crd_obj._template) + + def test__init_missing_parameter(self): + with self.assertRaises(exceptions.KubernetesCRDObjectDefinitionError): + kubernetes.CustomResourceDefinitionObject('ctx_name', + noname='name') + + +class NetworkObjectTestCase(base.BaseUnitTestCase): + + def setUp(self): + self.net_obj = kubernetes.NetworkObject(name='fake_name', + plugin='fake_plugin', + args='fake_args') + + def test__init_missing_parameter(self): + with self.assertRaises( + exceptions.KubernetesNetworkObjectDefinitionError): + kubernetes.NetworkObject('network_name', plugin='plugin') + with self.assertRaises( + exceptions.KubernetesNetworkObjectDefinitionError): + kubernetes.NetworkObject('network_name', args='args') + + @mock.patch.object(kubernetes_utils, 'get_custom_resource_definition') + def test_crd(self, mock_get_crd): + mock_crd = mock.Mock() + mock_get_crd.return_value = mock_crd + net_obj = copy.deepcopy(self.net_obj) + self.assertEqual(mock_crd, net_obj.crd) + + def test_template(self): + net_obj = copy.deepcopy(self.net_obj) + expected = {'apiVersion': 'group.com/v2', + 'kind': kubernetes.NetworkObject.KIND, + 'metadata': { + 'name': 'fake_name'}, + 'plugin': 'fake_plugin', + 'args': 'fake_args'} + crd = mock.Mock() + crd.spec.group = 'group.com' + crd.spec.version = 'v2' + net_obj._crd = crd + self.assertEqual(expected, net_obj.template) + + def test_group(self): + net_obj = copy.deepcopy(self.net_obj) + net_obj._crd = mock.Mock() + net_obj._crd.spec.group = 'fake_group' + self.assertEqual('fake_group', net_obj.group) + + def test_version(self): + net_obj = copy.deepcopy(self.net_obj) + net_obj._crd = mock.Mock() + net_obj._crd.spec.version = 'version_4' + self.assertEqual('version_4', net_obj.version) + + def test_plural(self): + net_obj = copy.deepcopy(self.net_obj) + net_obj._crd = mock.Mock() + net_obj._crd.spec.names.plural = 'name_ending_in_s' + self.assertEqual('name_ending_in_s', net_obj.plural) + + def test_scope(self): + net_obj = copy.deepcopy(self.net_obj) + net_obj._crd = mock.Mock() + net_obj._crd.spec.scope = 'Cluster' + self.assertEqual('Cluster', net_obj.scope) + + @mock.patch.object(kubernetes_utils, 'create_network') + def test_create(self, mock_create_network): + net_obj = copy.deepcopy(self.net_obj) + net_obj._scope = 'scope' + net_obj._group = 'group' + net_obj._version = 'version' + net_obj._plural = 'plural' + net_obj._template = 'template' + net_obj._name = 'fake_name' + net_obj.create() + mock_create_network.assert_called_once_with( + 'scope', 'group', 'version', 'plural', 'template', 'fake_name') + + @mock.patch.object(kubernetes_utils, 'delete_network') + def test_delete(self, mock_delete_network): + net_obj = copy.deepcopy(self.net_obj) + net_obj._scope = 'scope' + net_obj._group = 'group' + net_obj._version = 'version' + net_obj._plural = 'plural' + net_obj._name = 'name' + net_obj.delete() + mock_delete_network.assert_called_once_with( + 'scope', 'group', 'version', 'plural', 'name', skip_codes=[404]) + + +class ServiceNodePortObjectTestCase(base.BaseUnitTestCase): + + def test__init(self): + with mock.patch.object(kubernetes.ServiceNodePortObject, '_add_port') \ + as mock_add_port: + kubernetes.ServiceNodePortObject( + 'fake_name', node_ports=[{'port': 80, 'name': 'web'}]) + + mock_add_port.assert_has_calls([mock.call(22, 'ssh', protocol='TCP'), + mock.call(80, 'web')]) + + @mock.patch.object(kubernetes.ServiceNodePortObject, '_add_port') + def test__init_missing_mandatory_parameters(self, *args): + with self.assertRaises( + exceptions.KubernetesServiceObjectDefinitionError): + kubernetes.ServiceNodePortObject( + 'fake_name', node_ports=[{'port': 80}]) + with self.assertRaises( + exceptions.KubernetesServiceObjectDefinitionError): + kubernetes.ServiceNodePortObject( + 'fake_name', node_ports=[{'name': 'web'}]) + + @mock.patch.object(kubernetes.ServiceNodePortObject, '_add_port') + def test__init_missing_bad_name(self, *args): + with self.assertRaises( + exceptions.KubernetesServiceObjectNameError): + kubernetes.ServiceNodePortObject( + 'fake_name', node_ports=[{'port': 80, 'name': '-web'}]) + with self.assertRaises( + exceptions.KubernetesServiceObjectNameError): + kubernetes.ServiceNodePortObject( + 'fake_name', node_ports=[{'port': 80, 'name': 'Web'}]) + with self.assertRaises( + exceptions.KubernetesServiceObjectNameError): + kubernetes.ServiceNodePortObject( + 'fake_name', node_ports=[{'port': 80, 'name': 'web-'}]) + + def test__add_port(self): + nodeport_object = kubernetes.ServiceNodePortObject('fake_name') + port_ssh = {'name': 'ssh', + 'port': 22, + 'protocol': 'TCP'} + port_definition = {'port': 80, + 'protocol': 'TCP', + 'name': 'web', + 'targetPort': 10080, + 'nodePort': 30080} + port = copy.deepcopy(port_definition) + _port = port.pop('port') + name = port.pop('name') + nodeport_object._add_port(_port, name, **port) + self.assertEqual([port_ssh, port_definition], + nodeport_object.template['spec']['ports']) + + @mock.patch.object(kubernetes_utils, 'create_service') + def test_create(self, mock_create_service): + nodeport_object = kubernetes.ServiceNodePortObject('fake_name') + nodeport_object.template = 'fake_template' + nodeport_object.create() + mock_create_service.assert_called_once_with('fake_template') + + @mock.patch.object(kubernetes_utils, 'delete_service') + def test_delete(self, mock_delete_service): + nodeport_object = kubernetes.ServiceNodePortObject('fake_name') + nodeport_object.delete() + mock_delete_service.assert_called_once_with('fake_name-service', + skip_codes=[404]) + + +class KubernetesTemplate(base.BaseUnitTestCase): + + def test_get_rc_by_name(self): + ctx_cfg = { + 'servers': { + 'host1': {'args': 'some data'} + } + } + k_template = kubernetes.KubernetesTemplate('k8s_name', ctx_cfg) + rc = k_template.get_rc_by_name('host1-k8s_name') + self.assertTrue(isinstance(rc, kubernetes.ReplicationControllerObject)) + + def test_get_rc_by_name_wrong_name(self): + ctx_cfg = { + 'servers': { + 'host1': {'args': 'some data'} + } + } + k_template = kubernetes.KubernetesTemplate('k8s_name', ctx_cfg) + self.assertIsNone(k_template.get_rc_by_name('wrong_host_name')) + + def test_get_rc_by_name_no_rcs(self): + ctx_cfg = {'servers': {}} + k_template = kubernetes.KubernetesTemplate('k8s_name', ctx_cfg) + self.assertIsNone(k_template.get_rc_by_name('any_host_name')) diff --git a/yardstick/tests/unit/service/test_environment.py b/yardstick/tests/unit/service/test_environment.py index 4af9a3958..779e6eaa0 100644 --- a/yardstick/tests/unit/service/test_environment.py +++ b/yardstick/tests/unit/service/test_environment.py @@ -6,16 +6,15 @@ # 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 +from yardstick.common import exceptions +from yardstick.service import environment +from yardstick.tests.unit import base as ut_base -class EnvironmentTestCase(unittest.TestCase): +class EnvironmentTestCase(ut_base.BaseUnitTestCase): def test_get_sut_info(self): pod_info = { @@ -31,19 +30,17 @@ class EnvironmentTestCase(unittest.TestCase): ] } - 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() + with mock.patch.object(environment.AnsibleCommon, + 'gen_inventory_ini_dict'), \ + mock.patch.object(environment.AnsibleCommon, 'get_sut_info', + return_value={'node1': {}}), \ + mock.patch.object(environment.Environment, '_format_sut_info'): + env = environment.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 = environment.Environment(pod=pod_info) + with self.assertRaises(exceptions.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 57dacbcd3..5d3520986 100644 --- a/yardstick/tests/unit/test_cmd/commands/test_env.py +++ b/yardstick/tests/unit/test_cmd/commands/test_env.py @@ -6,60 +6,64 @@ # which accompanies this distribution, and is available at # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -from __future__ import absolute_import -import unittest + +import os +import sys + import mock import uuid -from yardstick.cmd.commands.env import EnvCommand +from yardstick.cmd.commands import env +from yardstick.tests.unit import base -class EnvCommandTestCase(unittest.TestCase): +class EnvCommandTestCase(base.BaseUnitTestCase): - @mock.patch('yardstick.cmd.commands.env.EnvCommand._start_async_task') - @mock.patch('yardstick.cmd.commands.env.EnvCommand._check_status') + @mock.patch.object(env.EnvCommand, '_start_async_task') + @mock.patch.object(env.EnvCommand, '_check_status') def test_do_influxdb(self, check_status_mock, start_async_task_mock): - env = EnvCommand() - env.do_influxdb({}) + _env = env.EnvCommand() + _env.do_influxdb({}) 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') + @mock.patch.object(env.EnvCommand, '_start_async_task') + @mock.patch.object(env.EnvCommand, '_check_status') def test_do_grafana(self, check_status_mock, start_async_task_mock): - env = EnvCommand() - env.do_grafana({}) + _env = env.EnvCommand() + _env.do_grafana({}) 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') + @mock.patch.object(env.EnvCommand, '_start_async_task') + @mock.patch.object(env.EnvCommand, '_check_status') def test_do_prepare(self, check_status_mock, start_async_task_mock): - env = EnvCommand() - env.do_prepare({}) + _env = env.EnvCommand() + _env.do_prepare({}) start_async_task_mock.assert_called_once() check_status_mock.assert_called_once() - @mock.patch('yardstick.cmd.commands.env.HttpClient.post') + @mock.patch.object(env.HttpClient, 'post') def test_start_async_task(self, post_mock): data = {'action': 'create_grafana'} - EnvCommand()._start_async_task(data) + env.EnvCommand()._start_async_task(data) post_mock.assert_called_once() - @mock.patch('yardstick.cmd.commands.env.HttpClient.get') - @mock.patch('yardstick.cmd.commands.env.EnvCommand._print_status') - def test_check_status(self, print_mock, get_mock): - # pylint: disable=unused-argument - # NOTE(ralonsoh): the pylint exception must be removed. The mocked - # command call must be tested. + @mock.patch.object(env.HttpClient, 'get') + @mock.patch.object(env.EnvCommand, '_print_status') + def test_check_status(self, mock_print, mock_get): task_id = str(uuid.uuid4()) - get_mock.return_value = {'status': 2, 'result': 'error'} - status = EnvCommand()._check_status(task_id, 'hello world') - self.assertEqual(status, 2) + mock_get.return_value = {'status': 2, 'result': 'error'} + self.assertEqual( + 2, env.EnvCommand()._check_status(task_id, 'hello world')) + self.assertEqual(2, mock_print.call_count) - def test_print_status(self): - try: - EnvCommand()._print_status('hello', 'word') - except Exception as e: # pylint: disable=broad-except - # NOTE(ralonsoh): try to reduce the scope of this exception. - self.assertIsInstance(e, IndexError) + @mock.patch.object(sys, 'stdout') + @mock.patch.object(os, 'popen') + def test_print_status(self, mock_popen, mock_stdout): + mock_popen_obj = mock.Mock() + mock_popen_obj.read.return_value = '' + mock_popen.return_value = mock_popen_obj + env.EnvCommand()._print_status('hello', 'word') + mock_stdout.write.assert_not_called() + mock_stdout.flush.assert_not_called() diff --git a/yardstick/tests/unit/test_cmd/test_NSBperf.py b/yardstick/tests/unit/test_cmd/test_NSBperf.py index d64b0c551..5de892212 100644 --- a/yardstick/tests/unit/test_cmd/test_NSBperf.py +++ b/yardstick/tests/unit/test_cmd/test_NSBperf.py @@ -11,15 +11,15 @@ # 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. -# -from __future__ import absolute_import -import unittest -import mock -import subprocess +import argparse import os +import subprocess + +import mock +from six.moves import builtins +import unittest -from yardstick.cmd.NSBperf import YardstickNSCli from yardstick.cmd import NSBperf @@ -32,30 +32,39 @@ class TestHandler(unittest.TestCase): class TestYardstickNSCli(unittest.TestCase): + + def setUp(self): + self._mock_print = mock.patch.object(builtins, 'print') + self.mock_print = self._mock_print.start() + self.addCleanup(self._stop_mocks) + + def _stop_mocks(self): + self._mock_print.stop() + def test___init__(self): - yardstick_ns_cli = YardstickNSCli() + yardstick_ns_cli = NSBperf.YardstickNSCli() self.assertIsNotNone(yardstick_ns_cli) def test_generate_final_report(self): - yardstick_ns_cli = YardstickNSCli() + yardstick_ns_cli = NSBperf.YardstickNSCli() test_case = "tc_baremetal_rfc2544_ipv4_1flow_1518B.yaml" if os.path.isfile("/tmp/yardstick.out"): os.remove('/tmp/yardstick.out') self.assertIsNone(yardstick_ns_cli.generate_final_report(test_case)) def test_generate_kpi_results(self): - yardstick_ns_cli = YardstickNSCli() + yardstick_ns_cli = NSBperf.YardstickNSCli() tkey = "cpu" tgen = {"cpu": {"ipc": 0}} self.assertIsNone(yardstick_ns_cli.generate_kpi_results(tkey, tgen)) def test_generate_nfvi_results(self): - yardstick_ns_cli = YardstickNSCli() + yardstick_ns_cli = NSBperf.YardstickNSCli() nfvi = {"collect_stats": {"cpu": {"ipc": 0, "Hz": 2.6}}} self.assertIsNone(yardstick_ns_cli.generate_nfvi_results(nfvi)) def test_handle_list_options(self): - yardstick_ns_cli = YardstickNSCli() + yardstick_ns_cli = NSBperf.YardstickNSCli() CLI_PATH = os.path.dirname(os.path.realpath(__file__)) repo_dir = CLI_PATH + "/../../../" test_path = os.path.join(repo_dir, "../samples/vnf_samples/nsut/") @@ -68,16 +77,21 @@ class TestYardstickNSCli(unittest.TestCase): args, test_path) def test_main(self): - yardstick_ns_cli = YardstickNSCli() + yardstick_ns_cli = NSBperf.YardstickNSCli() yardstick_ns_cli.parse_arguments = mock.Mock(return_value=0) yardstick_ns_cli.handle_list_options = mock.Mock(return_value=0) yardstick_ns_cli.terminate_if_less_options = mock.Mock(return_value=0) yardstick_ns_cli.run_test = mock.Mock(return_value=0) self.assertIsNone(yardstick_ns_cli.main()) - def test_parse_arguments(self): - yardstick_ns_cli = YardstickNSCli() - self.assertRaises(SystemExit, yardstick_ns_cli.parse_arguments) + @mock.patch.object(argparse.ArgumentParser, 'parse_args') + def test_parse_arguments(self, mock_parse): + class DummyArgs(object): + var1 = 'value1' + + mock_parse.return_value = DummyArgs + yardstick_ns_cli = NSBperf.YardstickNSCli() + self.assertIn('var1', yardstick_ns_cli.parse_arguments()) def test_run_test(self): cur_dir = os.getcwd() @@ -85,7 +99,7 @@ class TestYardstickNSCli(unittest.TestCase): YARDSTICK_REPOS_DIR = os.path.join(CLI_PATH + "/../../") test_path = os.path.join(YARDSTICK_REPOS_DIR, "../samples/vnf_samples/nsut/") - yardstick_ns_cli = YardstickNSCli() + yardstick_ns_cli = NSBperf.YardstickNSCli() subprocess.check_output = mock.Mock(return_value=0) args = {"vnf": "vpe", "test": "tc_baremetal_rfc2544_ipv4_1flow_1518B.yaml"} @@ -103,13 +117,13 @@ class TestYardstickNSCli(unittest.TestCase): os.chdir(cur_dir) def test_terminate_if_less_options(self): - yardstick_ns_cli = YardstickNSCli() + yardstick_ns_cli = NSBperf.YardstickNSCli() args = {"vnf": False} self.assertRaises(SystemExit, yardstick_ns_cli.terminate_if_less_options, args) def test_validate_input(self): - yardstick_ns_cli = YardstickNSCli() + yardstick_ns_cli = NSBperf.YardstickNSCli() self.assertEqual(1, yardstick_ns_cli.validate_input("", 4)) NSBperf.input = lambda _: 'yes' self.assertEqual(1, yardstick_ns_cli.validate_input(5, 4)) diff --git a/yardstick/tests/unit/test_ssh.py b/yardstick/tests/unit/test_ssh.py index f92290070..71929f1a2 100644 --- a/yardstick/tests/unit/test_ssh.py +++ b/yardstick/tests/unit/test_ssh.py @@ -13,10 +13,6 @@ # License for the specific language governing permissions and limitations # under the License. -# yardstick comment: this file is a modified copy of -# rally/tests/unit/common/test_sshutils.py - -from __future__ import absolute_import import os import socket import unittest @@ -26,8 +22,8 @@ from itertools import count import mock from oslo_utils import encodeutils +from yardstick.common import exceptions from yardstick import ssh -from yardstick.ssh import SSHError, SSHTimeout from yardstick.ssh import SSH from yardstick.ssh import AutoConnectSSH @@ -127,7 +123,7 @@ class SSHTestCase(unittest.TestCase): dss = mock_paramiko.dsskey.DSSKey rsa.from_private_key.side_effect = mock_paramiko.SSHException dss.from_private_key.side_effect = mock_paramiko.SSHException - self.assertRaises(ssh.SSHError, self.test_client._get_pkey, "key") + self.assertRaises(exceptions.SSHError, self.test_client._get_pkey, "key") @mock.patch("yardstick.ssh.six.moves.StringIO") @mock.patch("yardstick.ssh.paramiko") @@ -194,13 +190,13 @@ class SSHTestCase(unittest.TestCase): test_ssh = ssh.SSH("admin", "example.net", pkey="key") - with self.assertRaises(SSHError) as raised: + with self.assertRaises(exceptions.SSHError) as raised: test_ssh._get_client() - self.assertEqual(mock_paramiko.SSHClient.call_count, 1) - self.assertEqual(mock_paramiko.AutoAddPolicy.call_count, 1) - self.assertEqual(fake_client.set_missing_host_key_policy.call_count, 1) - self.assertEqual(fake_client.connect.call_count, 1) + mock_paramiko.SSHClient.assert_called_once() + mock_paramiko.AutoAddPolicy.assert_called_once() + fake_client.set_missing_host_key_policy.assert_called_once() + fake_client.connect.assert_called_once() exc_str = str(raised.exception) self.assertIn('raised during connect', exc_str) self.assertIn('MyError', exc_str) @@ -242,21 +238,40 @@ class SSHTestCase(unittest.TestCase): self.assertEqual("stdout fake data", stdout) self.assertEqual("stderr fake data", stderr) + @mock.patch("yardstick.ssh.six.moves.StringIO") + def test_execute_raise_on_error_passed(self, mock_string_io): + mock_string_io.side_effect = stdio = [mock.Mock(), mock.Mock()] + stdio[0].read.return_value = "stdout fake data" + stdio[1].read.return_value = "stderr fake data" + with mock.patch.object(self.test_client, "run", return_value=0) \ + as mock_run: + status, stdout, stderr = self.test_client.execute( + "cmd", + stdin="fake_stdin", + timeout=43, + raise_on_error=True) + mock_run.assert_called_once_with( + "cmd", stdin="fake_stdin", stdout=stdio[0], + stderr=stdio[1], timeout=43, raise_on_error=True) + self.assertEqual(0, status) + self.assertEqual("stdout fake data", stdout) + self.assertEqual("stderr fake data", stderr) + @mock.patch("yardstick.ssh.time") def test_wait_timeout(self, mock_time): mock_time.time.side_effect = [1, 50, 150] - self.test_client.execute = mock.Mock(side_effect=[ssh.SSHError, - ssh.SSHError, + self.test_client.execute = mock.Mock(side_effect=[exceptions.SSHError, + exceptions.SSHError, 0]) - self.assertRaises(ssh.SSHTimeout, self.test_client.wait) + self.assertRaises(exceptions.SSHTimeout, self.test_client.wait) self.assertEqual([mock.call("uname")] * 2, self.test_client.execute.mock_calls) @mock.patch("yardstick.ssh.time") def test_wait(self, mock_time): mock_time.time.side_effect = [1, 50, 100] - self.test_client.execute = mock.Mock(side_effect=[ssh.SSHError, - ssh.SSHError, + self.test_client.execute = mock.Mock(side_effect=[exceptions.SSHError, + exceptions.SSHError, 0]) self.test_client.wait() self.assertEqual([mock.call("uname")] * 3, @@ -333,7 +348,7 @@ class SSHRunTestCase(unittest.TestCase): def test_run_nonzero_status(self, mock_select): mock_select.select.return_value = ([], [], []) self.fake_session.recv_exit_status.return_value = 1 - self.assertRaises(ssh.SSHError, self.test_client.run, "cmd") + self.assertRaises(exceptions.SSHError, self.test_client.run, "cmd") self.assertEqual(1, self.test_client.run("cmd", raise_on_error=False)) @mock.patch("yardstick.ssh.select") @@ -401,7 +416,7 @@ class SSHRunTestCase(unittest.TestCase): def test_run_select_error(self, mock_select): self.fake_session.exit_status_ready.return_value = False mock_select.select.return_value = ([], [], [True]) - self.assertRaises(ssh.SSHError, self.test_client.run, "cmd") + self.assertRaises(exceptions.SSHError, self.test_client.run, "cmd") @mock.patch("yardstick.ssh.time") @mock.patch("yardstick.ssh.select") @@ -409,7 +424,7 @@ class SSHRunTestCase(unittest.TestCase): mock_time.time.side_effect = [1, 3700] mock_select.select.return_value = ([], [], []) self.fake_session.exit_status_ready.return_value = False - self.assertRaises(ssh.SSHTimeout, self.test_client.run, "cmd") + self.assertRaises(exceptions.SSHTimeout, self.test_client.run, "cmd") @mock.patch("yardstick.ssh.open", create=True) def test__put_file_shell(self, mock_open): @@ -514,7 +529,7 @@ class TestAutoConnectSSH(unittest.TestCase): auto_connect_ssh._get_client = mock__get_client = mock.Mock() auto_connect_ssh._connect() - self.assertEqual(mock__get_client.call_count, 1) + mock__get_client.assert_called_once() def test___init___negative(self): with self.assertRaises(TypeError): @@ -529,9 +544,9 @@ class TestAutoConnectSSH(unittest.TestCase): auto_connect_ssh = AutoConnectSSH('user1', 'host1', wait=10) auto_connect_ssh._get_client = mock__get_client = mock.Mock() - mock__get_client.side_effect = SSHError + mock__get_client.side_effect = exceptions.SSHError - with self.assertRaises(SSHTimeout): + with self.assertRaises(exceptions.SSHTimeout): auto_connect_ssh._connect() self.assertEqual(mock_time.time.call_count, 12) @@ -547,7 +562,7 @@ class TestAutoConnectSSH(unittest.TestCase): auto_connect_ssh.get_file_obj('remote/path', mock.Mock()) - self.assertEqual(mock_sftp.getfo.call_count, 1) + mock_sftp.getfo.assert_called_once() def test__make_dict(self): auto_connect_ssh = AutoConnectSSH('user1', 'host1') @@ -584,7 +599,7 @@ class TestAutoConnectSSH(unittest.TestCase): auto_connect_ssh.put('a', 'z') with mock_scp_client_type() as mock_scp_client: - self.assertEqual(mock_scp_client.put.call_count, 1) + mock_scp_client.put.assert_called_once() @mock.patch('yardstick.ssh.SCPClient') def test_get(self, mock_scp_client_type): @@ -593,7 +608,7 @@ class TestAutoConnectSSH(unittest.TestCase): auto_connect_ssh.get('a', 'z') with mock_scp_client_type() as mock_scp_client: - self.assertEqual(mock_scp_client.get.call_count, 1) + mock_scp_client.get.assert_called_once() def test_put_file(self): auto_connect_ssh = AutoConnectSSH('user1', 'host1') @@ -601,4 +616,27 @@ class TestAutoConnectSSH(unittest.TestCase): auto_connect_ssh._put_file_sftp = mock_put_sftp = mock.Mock() auto_connect_ssh.put_file('a', 'b') - self.assertEqual(mock_put_sftp.call_count, 1) + mock_put_sftp.assert_called_once() + + def test_execute(self): + auto_connect_ssh = AutoConnectSSH('user1', 'host1') + auto_connect_ssh._client = mock.Mock() + auto_connect_ssh.run = mock.Mock(return_value=0) + exit_code, _, _ = auto_connect_ssh.execute('') + self.assertEqual(exit_code, 0) + + def _mock_run(self, *args, **kwargs): + if args[0] == 'ls': + if kwargs.get('raise_on_error'): + raise exceptions.SSHError(error_msg='Command error') + return 1 + return 0 + + def test_execute_command_error(self): + auto_connect_ssh = AutoConnectSSH('user1', 'host1') + auto_connect_ssh._client = mock.Mock() + auto_connect_ssh.run = mock.Mock(side_effect=self._mock_run) + self.assertRaises(exceptions.SSHError, auto_connect_ssh.execute, 'ls', + raise_on_error=True) + exit_code, _, _ = auto_connect_ssh.execute('ls') + self.assertNotEqual(exit_code, 0) |