diff options
-rw-r--r-- | .gitignore | 5 | ||||
-rw-r--r-- | qtip/ansible_library/plugins/action/collect.py | 2 | ||||
-rw-r--r-- | qtip/cli/entry.py | 3 | ||||
-rw-r--r-- | resources/metric/nDPI.yaml | 80 | ||||
-rw-r--r-- | resources/template/dpi-metrics.j2 | 7 | ||||
-rw-r--r-- | resources/template/hosts.sample | 83 | ||||
-rw-r--r-- | resources/template/qpi-report.sample | 46 | ||||
-rw-r--r-- | resources/template/ssh.cfg.sample | 56 | ||||
-rw-r--r-- | resources/template/system-info.sample | 36 | ||||
-rw-r--r-- | setup.cfg | 1 | ||||
-rw-r--r-- | tests/integration/ansible.cfg | 2 | ||||
-rw-r--r-- | tests/integration/group_vars/all | 1 | ||||
-rw-r--r-- | tests/integration/run.yaml | 11 | ||||
-rw-r--r-- | tests/unit/cli/options_test.py | 3 | ||||
-rw-r--r-- | tests/unit/reporter/test_testapi.py | 116 |
15 files changed, 226 insertions, 226 deletions
@@ -75,7 +75,8 @@ ChangeLog !/tests/data/**/* # integration data +/tests/integration/*.retry +/tests/integration/dump /tests/integration/hosts +/tests/integration/reports /tests/integration/ssh.cfg -/tests/integration/*.retry -/tests/integration/reports/* diff --git a/qtip/ansible_library/plugins/action/collect.py b/qtip/ansible_library/plugins/action/collect.py index 26e813b8..8c825317 100644 --- a/qtip/ansible_library/plugins/action/collect.py +++ b/qtip/ansible_library/plugins/action/collect.py @@ -29,7 +29,7 @@ class ActionModule(ActionBase): dump = self._task.args.get('dump') if dump is not None: - dump_facts(task_vars['inventory_hostname'], [{'name': 'inxi.log', 'content': string}]) + dump_facts(task_vars['inventory_hostname'], [{'name': dump, 'content': string}]) return collect(patterns, string) diff --git a/qtip/cli/entry.py b/qtip/cli/entry.py index 6cf78b58..b84a03d0 100644 --- a/qtip/cli/entry.py +++ b/qtip/cli/entry.py @@ -9,6 +9,7 @@ import click import os +import pkg_resources as pkg import sys @@ -53,7 +54,7 @@ class QtipCli(click.MultiCommand): invoke_without_command=True) @click.option('-v', '--verbose', is_flag=True, help='Enable verbose mode.') @click.option('-d', '--debug', is_flag=True, help='Enable debug mode.') -@click.version_option('dev') +@click.version_option(pkg.require("qtip")[0]) @pass_context def cli(ctx, verbose, debug): if debug: diff --git a/resources/metric/nDPI.yaml b/resources/metric/nDPI.yaml new file mode 100644 index 00000000..0391302a --- /dev/null +++ b/resources/metric/nDPI.yaml @@ -0,0 +1,80 @@ +############################################################################## +# Copyright (c) 2017 ZTE Corporation 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 +############################################################################## + + +- name: prepare sample pcap file + get_url: + url: "https://build.opnfv.org/artifacts.opnfv.org/qtip/utilities/test.pcap" + dest: "{{ qtip_dump }}/localhost/{{ nDPI_file }}" + validate_certs: no # required when using proxy for https + run_once: yes + delegate_to: localhost + +- name: installing nDPI dependencies if CentOS + yum: + name: '{{ item }}' + state: present + when: ansible_os_family == "RedHat" + with_items: + - git + - gcc + - patch + - perl-Time-HiRes + - autofconf + - automake + - libpcap-devel libtool + +- name: installing nDPI dependencies if Ubuntu + apt: + name: build-essential + state: present + when: ansible_os_family == "Debian" + +- name: making nDPI temporary directory + file: + path: "{{ nDPI_cwd }}" + state: directory + +- name: clone nDPI + git: + repo: https://github.com/ntop/nDPI.git + dest: "{{ nDPI_cwd }}" + depth: 1 + update: no + +- name: build nDPI library + command: '{{ item }}' + with_items: + - ./autogen.sh + - ./configure + - make + args: + chdir: "{{ nDPI_cwd }}" + creates: example/ndpiReader + +- name: copy sample packet file + copy: + src: "{{ qtip_dump }}/localhost/{{ nDPI_file }}" + dest: "{{ nDPI_cwd }}/example/{{ nDPI_file }}" + +- name: + command: "./ndpiReader -i {{ nDPI_file }}" + args: + chdir: "{{ nDPI_cwd }}/example/" + register: nDPI_out + +- name: collect DPI metrics from nDPI + collect: + string: "{{ nDPI_out.stdout }}" + patterns: + # nDPI throughput: 1.46 M pps / 13.69 Gb/sec + # TODO(yujunz) convert "M pps" and "K pps" to number + - 'nDPI throughput:\s+?(?P<dpi_pps>\d+.\d+.*) \/ (?P<dpi_bps>\d+.\d+.*)$' + dump: 'nDPI.log' + register: dpi_metrics diff --git a/resources/template/dpi-metrics.j2 b/resources/template/dpi-metrics.j2 new file mode 100644 index 00000000..4de200b6 --- /dev/null +++ b/resources/template/dpi-metrics.j2 @@ -0,0 +1,7 @@ +nDPI throughput +=============== + +{% for host in groups['compute'] %} +{% set dpi_metrics=hostvars[host].dpi_metrics %} +{{ (hostvars[host].ansible_hostname, "{} / {}".format(dpi_metrics.dpi_pps[0], dpi_metrics.dpi_bps[0]))|justify }} +{% endfor %} diff --git a/resources/template/hosts.sample b/resources/template/hosts.sample deleted file mode 100644 index e37d38ec..00000000 --- a/resources/template/hosts.sample +++ /dev/null @@ -1,83 +0,0 @@ -[fuel-master] -fuel-master - -[local] -localhost ansible_connection=local - -[fuel-groups:children] -ceph-osd -cluster-1 -compute -controller -hw-zte-servers -mongo -node-1 -node-2 -node-3 -node-4 -node-5 -node-6 -node-7 - -[fuel-groups:vars] -ansible_ssh_common_args=-F ./ssh.cfg - -[ceph-osd] -node-2 -node-4 -node-6 -node-7 - -[cluster-1] -node-1 -node-2 -node-3 -node-4 -node-5 -node-6 -node-7 - -[compute] -node-2 -node-4 -node-6 -node-7 - -[controller] -node-1 -node-3 -node-5 - -[hw-zte-servers] -node-1 -node-2 -node-3 -node-4 -node-5 -node-6 -node-7 - -[mongo] -node-1 - -[node-1] -node-1 - -[node-2] -node-2 - -[node-3] -node-3 - -[node-4] -node-4 - -[node-5] -node-5 - -[node-6] -node-6 - -[node-7] -node-7 - diff --git a/resources/template/qpi-report.sample b/resources/template/qpi-report.sample deleted file mode 100644 index cb9e9308..00000000 --- a/resources/template/qpi-report.sample +++ /dev/null @@ -1,46 +0,0 @@ -Sample QPI Report - -Host: node-26 -QPI: 1.41147857985 -Spec: compute - -- SSL: 1.41147857985 - - ssl_rsa: 1.41147857985 - - rsa_sign_512: 1.25261808935 - - rsa_verify_512: 1.33973907536 - - rsa_sign_1024: 1.31933223495 - - rsa_verify_1024: 1.46972456907 - - rsa_sign_2048: 1.8615470852 - - rsa_verify_2048: 1.3683903146 - - rsa_sign_4096: 1.31537708129 - - rsa_verify_4096: 1.36510018898 - -Host: node-28 -QPI: 1.28082308651 -Spec: compute - -- SSL: 1.28082308651 - - ssl_rsa: 1.28082308651 - - rsa_sign_512: 1.13628081136 - - rsa_verify_512: 1.24882238433 - - rsa_sign_1024: 1.16100601465 - - rsa_verify_1024: 1.33382620817 - - rsa_sign_2048: 1.72057174888 - - rsa_verify_2048: 1.23917640038 - - rsa_sign_4096: 1.16846229187 - - rsa_verify_4096: 1.2384388324 - -Host: node-27 -QPI: 1.41542492777 -Spec: compute - -- SSL: 1.41542492777 - - ssl_rsa: 1.41542492777 - - rsa_sign_512: 1.25857845591 - - rsa_verify_512: 1.34193319426 - - rsa_sign_1024: 1.32097981222 - - rsa_verify_1024: 1.4807103336 - - rsa_sign_2048: 1.86378923767 - - rsa_verify_2048: 1.36600306932 - - rsa_sign_4096: 1.31635651322 - - rsa_verify_4096: 1.37504880601 diff --git a/resources/template/ssh.cfg.sample b/resources/template/ssh.cfg.sample deleted file mode 100644 index efa45ab6..00000000 --- a/resources/template/ssh.cfg.sample +++ /dev/null @@ -1,56 +0,0 @@ -Host node-5 - HostName 10.20.5.12 - User root - # Use `ProxyCommand` for OpenSSH before 7.3 - ProxyCommand ssh -o 'ForwardAgent yes' fuel-master 'ssh-add && nc %h %p' - # `ProxyJump` is available since OpenSSH 7.3 - # ProxyJump fuel-master - -Host node-4 - HostName 10.20.5.14 - User root - # Use `ProxyCommand` for OpenSSH before 7.3 - ProxyCommand ssh -o 'ForwardAgent yes' fuel-master 'ssh-add && nc %h %p' - # `ProxyJump` is available since OpenSSH 7.3 - # ProxyJump fuel-master - -Host node-7 - HostName 10.20.5.15 - User root - # Use `ProxyCommand` for OpenSSH before 7.3 - ProxyCommand ssh -o 'ForwardAgent yes' fuel-master 'ssh-add && nc %h %p' - # `ProxyJump` is available since OpenSSH 7.3 - # ProxyJump fuel-master - -Host node-6 - HostName 10.20.5.16 - User root - # Use `ProxyCommand` for OpenSSH before 7.3 - ProxyCommand ssh -o 'ForwardAgent yes' fuel-master 'ssh-add && nc %h %p' - # `ProxyJump` is available since OpenSSH 7.3 - # ProxyJump fuel-master - -Host node-1 - HostName 10.20.5.10 - User root - # Use `ProxyCommand` for OpenSSH before 7.3 - ProxyCommand ssh -o 'ForwardAgent yes' fuel-master 'ssh-add && nc %h %p' - # `ProxyJump` is available since OpenSSH 7.3 - # ProxyJump fuel-master - -Host node-3 - HostName 10.20.5.11 - User root - # Use `ProxyCommand` for OpenSSH before 7.3 - ProxyCommand ssh -o 'ForwardAgent yes' fuel-master 'ssh-add && nc %h %p' - # `ProxyJump` is available since OpenSSH 7.3 - # ProxyJump fuel-master - -Host node-2 - HostName 10.20.5.13 - User root - # Use `ProxyCommand` for OpenSSH before 7.3 - ProxyCommand ssh -o 'ForwardAgent yes' fuel-master 'ssh-add && nc %h %p' - # `ProxyJump` is available since OpenSSH 7.3 - # ProxyJump fuel-master - diff --git a/resources/template/system-info.sample b/resources/template/system-info.sample deleted file mode 100644 index 371243e2..00000000 --- a/resources/template/system-info.sample +++ /dev/null @@ -1,36 +0,0 @@ -System Information from inxi -============================ - -node-26 ------------------------------ - -CPU Brand.................2 Deca core Intel Xeon E5-2650 v3s (-HT-MCP-SMP-) speed/max: 1200/3000 MHz -Disk............................................................................1200.3GB (0.8% used) -Host Name.........................................................................node-26.zte.com.cn -Kernel..............................................................4.4.0-66-generic x86_64 (64 bit) -Memory.............................................................................3836.1/128524.1MB -Operating System.................................................................Ubuntu 16.04 xenial -Product......................................................................................EC600G3 - -node-28 ------------------------------ - -CPU Brand.................2 Deca core Intel Xeon E5-2650 v3s (-HT-MCP-SMP-) speed/max: 1200/3000 MHz -Disk............................................................................1200.3GB (0.8% used) -Host Name.........................................................................node-28.zte.com.cn -Kernel..............................................................4.4.0-66-generic x86_64 (64 bit) -Memory.............................................................................3826.6/128524.1MB -Operating System.................................................................Ubuntu 16.04 xenial -Product......................................................................................EC600G3 - -node-27 ------------------------------ - -CPU Brand.................2 Deca core Intel Xeon E5-2650 v3s (-HT-MCP-SMP-) speed/max: 1200/3000 MHz -Disk............................................................................1200.3GB (0.8% used) -Host Name.........................................................................node-27.zte.com.cn -Kernel..............................................................4.4.0-66-generic x86_64 (64 bit) -Memory.............................................................................3922.4/128524.1MB -Operating System.................................................................Ubuntu 16.04 xenial -Product......................................................................................EC600G3 - @@ -1,5 +1,6 @@ [metadata] name = qtip +version = 5.0.0 summary = Platform Performance Benchmarking description-file = README.md diff --git a/tests/integration/ansible.cfg b/tests/integration/ansible.cfg index 40e28bcf..30e28480 100644 --- a/tests/integration/ansible.cfg +++ b/tests/integration/ansible.cfg @@ -26,3 +26,5 @@ filter_plugins = ../../qtip/ansible_library/plugins/filter #test_plugins = /usr/share/ansible/plugins/test #terminal_plugins = /usr/share/ansible/plugins/terminal #strategy_plugins = /usr/share/ansible/plugins/strategy + +callback_whitelist = profile_tasks diff --git a/tests/integration/group_vars/all b/tests/integration/group_vars/all index 16a93f46..a84ab51f 100644 --- a/tests/integration/group_vars/all +++ b/tests/integration/group_vars/all @@ -1,3 +1,4 @@ qtip_resources: ../../resources qtip_reports: ./reports qtip_fixtures: ./fixtures +qtip_dump: ./dump diff --git a/tests/integration/run.yaml b/tests/integration/run.yaml index 10428ac3..e715863f 100644 --- a/tests/integration/run.yaml +++ b/tests/integration/run.yaml @@ -21,6 +21,12 @@ - name: ssl metrics include: "{{ qtip_resources }}/metric/openssl.yaml" tags: [ssl] + - name: DPI metrics + include: "{{ qtip_resources }}/metric/nDPI.yaml" + vars: + nDPI_cwd: "{{ ansible_env.HOME }}/qtip/nDPI" + nDPI_file: "dpi.pcap" + tags: [dpi] - hosts: compute tasks: @@ -57,6 +63,11 @@ src: "{{ qtip_resources }}/template/qpi-report.j2" dest: "{{ qtip_reports }}/qpi-report" tags: [report] + - name: create dpi metrics report + template: + src: "{{ qtip_resources }}/template/dpi-metrics.j2" + dest: "{{ qtip_reports }}/dpi-metrics" + tags: [report, dpi] - name: push result to testapi uri: url: "{{ testapi_url }}/results" diff --git a/tests/unit/cli/options_test.py b/tests/unit/cli/options_test.py index 9dbbe6f3..d7c0f700 100644 --- a/tests/unit/cli/options_test.py +++ b/tests/unit/cli/options_test.py @@ -8,6 +8,7 @@ ############################################################################## import pytest +import re import sys from click.testing import CliRunner @@ -26,7 +27,7 @@ class TestClass(object): def test_version(self, runner): result = runner.invoke(cli, ['--version']) - assert 'dev' in result.output + assert re.search(r'\d+\.\d+\.\d+', result.output) def test_debug(self, runner): runner.invoke(cli, ['-d']) diff --git a/tests/unit/reporter/test_testapi.py b/tests/unit/reporter/test_testapi.py new file mode 100644 index 00000000..85655274 --- /dev/null +++ b/tests/unit/reporter/test_testapi.py @@ -0,0 +1,116 @@ +############################################################################## +# Copyright (c) 2017 akhil.batra@research.iiit.ac.in 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 pytest + +from qtip.reporter import testapi + + +@pytest.mark.parametrize("testapi_url, payload", [ + ("http://testresults.opnfv.org/test/api/v1", {'project_name': 'qtip', + 'case_name': 'fake-case', + 'pod_name': 'fake_pod', + 'installer': 'fake_installer', + 'version': '1', + 'scenario': 'fake_scenario', + 'criteria': 'fake_criteria', + 'build_tag': 'fake_tag', + 'start_date': 'fake_date', + 'stop_date': 'fake_date', + 'details': 'fake:details'}), +]) +@mock.patch('qtip.reporter.testapi.requests') +def test_testapi_unavailable(mock_request, testapi_url, payload): + mock_request.post.return_value.status_code = testapi.requests.codes.unavailable + mock_request.post.return_value.reason = 'Service unavailable' + testapi.push_results(testapi_url, payload) + mock_request.post.assert_called_with(testapi_url + '/results', json=payload) + mock_request.post.return_value.raise_for_status.assert_called() + + +@pytest.mark.parametrize("testapi_url, payload", [ + ("http://testresults.opnfv.org/test/api/v1", {'project_name': 'qtip', + 'case_name': 'fake-case', + 'pod_name': 'fake_pod', + 'installer': 'fake_installer', + 'version': '1', + 'scenario': 'fake_scenario', + 'criteria': 'fake_criteria', + 'build_tag': 'fake_tag', + 'start_date': 'fake_date', + 'stop_date': 'fake_date', + 'details': 'fake:details'}), +]) +@mock.patch('qtip.reporter.testapi.requests') +def test_push_results_success(mock_request, testapi_url, payload): + mock_request.post.return_value.status_code = testapi.requests.codes.ok + mock_request.post.return_value.json.return_value = {'href': 'mock_url'} + push_response = testapi.push_results(testapi_url, payload) + mock_request.post.assert_called_with(testapi_url + '/results', json=payload) + assert push_response['href'] == 'mock_url' + + +@pytest.mark.parametrize("testapi_url, payload", [ + ("http://testresults.opnfv.org/test/api/v1", {'project_name': 'qtip', + 'case_name': 'fake-case', + 'pod_name': 'fake_pod', + 'installer': 'fake_installer', + 'version': '1', + 'scenario': 'fake_scenario', + 'criteria': 'fake_criteria', + 'build_tag': 'fake_tag', + 'start_date': 'fake_date', + 'stop_date': 'fake_date', + 'details': 'fake:details'}), +]) +@mock.patch('qtip.reporter.testapi.requests') +def test_push_results_not_found(mock_request, testapi_url, payload): + mock_request.post.return_value.status_code = testapi.requests.codes.not_found + mock_request.post.return_value.reason = 'Not found' + testapi.push_results(testapi_url, payload) + mock_request.post.assert_called_with(testapi_url + '/results', json=payload) + mock_request.post.return_value.raise_for_status.assert_called() + + +@pytest.mark.parametrize("testapi_url, payload", [ + ("http://testresults.opnfv.org/test/api/v1", {'project_name': 'qtip', + 'case_name': 'fake-case', + 'pod_name': 'fake_pod', + 'installer': 'fake_installer', + 'version': '', + 'scenario': None, + 'criteria': 'fake_criteria', + 'build_tag': 'fake_tag', + 'start_date': 'fake_date', + 'stop_date': 'fake_date', + 'details': 'fake:details'}), +]) +def test_push_results_invalid_params(testapi_url, payload): + with pytest.raises(testapi.InvalidParamsError) as error_invalid: + testapi.push_results(testapi_url, payload) + assert set(error_invalid.value.params) == {'version', 'scenario'} + + +@pytest.mark.parametrize("testapi_url, payload", [ + ("http://testresults.opnfv.org/test/api/v1", {'project_name': 'qtip', + 'case_name': 'fake-case', + 'pod_name': 'fake_pod', + 'installer': 'fake_installer', + 'criteria': 'fake_criteria', + 'build_tag': 'fake_tag', + 'start_date': 'fake_date', + 'stop_date': 'fake_date', + 'details': 'fake:details'}), +]) +def test_push_results_missing_params(testapi_url, payload): + with pytest.raises(testapi.MissingParamsError) as error_missing: + testapi.push_results(testapi_url, payload) + assert set(error_missing.value.params) == {'version', 'scenario'} |