aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DEVELOP.md75
-rw-r--r--benchmarks/QPI/compute.yaml37
-rw-r--r--benchmarks/metric/dhrystone.yaml17
-rw-r--r--benchmarks/metric/dpi.yaml (renamed from qtip/driver/sample.py)14
-rw-r--r--benchmarks/metric/ramspeed.yaml13
-rw-r--r--benchmarks/metric/ssl.yaml13
-rw-r--r--benchmarks/metric/whetstone.yaml18
-rw-r--r--benchmarks/plan/compute.yaml120
-rw-r--r--benchmarks/plan/sample.yaml (renamed from qtip/driver/yardstick.py)14
-rw-r--r--collector/2017-03-16-20-07/result.json265
-rw-r--r--collector/timeline.json39
-rw-r--r--docker/Dockerfile9
-rw-r--r--docker/Dockerfile.aarch64.patch33
-rw-r--r--docs/release/release-notes/index.rst2
-rw-r--r--docs/testing/developer/design/apidocs/index.rst (renamed from docs/development/design/apidocs/index.rst)0
-rw-r--r--docs/testing/developer/design/apidocs/qtip_restful_api.rst (renamed from docs/development/design/apidocs/qtip_restful_api.rst)0
-rw-r--r--docs/testing/developer/design/cli.rst92
-rw-r--r--docs/testing/developer/design/compute_QPI.rst (renamed from docs/development/design/compute_QPI.rst)0
-rw-r--r--docs/testing/developer/design/dashboard.rst (renamed from docs/development/design/dashboard.rst)0
-rw-r--r--docs/testing/developer/design/index.rst (renamed from docs/development/design/index.rst)0
-rw-r--r--docs/testing/developer/design/integration_with_yardstick.rst (renamed from docs/development/design/integration_with_yardstick.rst)0
-rw-r--r--docs/testing/developer/overview/.gitkeep (renamed from docs/development/overview/.gitkeep)0
-rw-r--r--docs/testing/developer/requirement/.gitkeep (renamed from docs/development/requirement/.gitkeep)0
-rw-r--r--docs/testing/user/.gitkeep (renamed from docs/release/installation/.gitkeep)0
-rw-r--r--docs/testing/user/configguide/configuration.rst (renamed from docs/release/configguide/configuration.rst)0
-rw-r--r--docs/testing/user/configguide/index.rst (renamed from docs/release/configguide/index.rst)0
-rw-r--r--docs/testing/user/installation/.gitkeep (renamed from docs/release/scenarios/.gitkeep)0
-rw-r--r--docs/testing/user/scenarios/.gitkeep (renamed from qtip/driver/ansible/__init__.py)0
-rw-r--r--docs/testing/user/userguide/_01-compute.rst (renamed from docs/release/userguide/_01-compute.rst)0
-rw-r--r--docs/testing/user/userguide/_02-network.rst (renamed from docs/release/userguide/_02-network.rst)0
-rw-r--r--docs/testing/user/userguide/_03-storage.rst (renamed from docs/release/userguide/_03-storage.rst)0
-rw-r--r--docs/testing/user/userguide/_testcase_description.rst (renamed from docs/release/userguide/_testcase_description.rst)0
-rw-r--r--docs/testing/user/userguide/annex.rst (renamed from docs/release/userguide/annex.rst)0
-rw-r--r--docs/testing/user/userguide/benchmark-suites.rst (renamed from docs/release/userguide/benchmark-suites.rst)0
-rw-r--r--docs/testing/user/userguide/cli.rst38
-rw-r--r--docs/testing/user/userguide/index.rst (renamed from docs/release/userguide/index.rst)0
-rw-r--r--docs/testing/user/userguide/introduction.rst (renamed from docs/release/userguide/introduction.rst)0
-rw-r--r--legacy/assets/perftest/etc/dpi_average.sh14
-rw-r--r--opt/infra/roles/qtip/files/run_qtip_server.sh22
-rw-r--r--qtip/api/__main__.py24
-rw-r--r--qtip/api/controllers/common.py35
-rw-r--r--qtip/api/controllers/metric.py25
-rw-r--r--qtip/api/controllers/plan.py31
-rw-r--r--qtip/api/controllers/qpi.py25
-rw-r--r--qtip/api/swagger/swagger.yaml295
-rw-r--r--qtip/cli/commands/cmd_metric.py13
-rw-r--r--qtip/cli/commands/cmd_plan.py13
-rw-r--r--qtip/cli/commands/cmd_qpi.py13
-rw-r--r--qtip/cli/commands/cmd_report.py31
-rw-r--r--qtip/cli/entry.py29
-rw-r--r--qtip/cli/templates/metric.j26
-rw-r--r--qtip/cli/templates/plan.j22
-rw-r--r--qtip/cli/templates/qpi.j212
-rw-r--r--qtip/cli/utils.py31
-rw-r--r--qtip/collector/calculator.py38
-rw-r--r--qtip/collector/logfile.py11
-rw-r--r--qtip/collector/parser/grep.py72
-rw-r--r--qtip/collector/parser/regex.yaml85
-rw-r--r--qtip/driver/ansible_api.py58
-rw-r--r--qtip/driver/ansible_driver.py102
-rw-r--r--qtip/driver/playbook/bwn_ng.yaml (renamed from qtip/driver/ansible/playbook/bwn_ng.yaml)4
-rw-r--r--qtip/driver/playbook/dpi/clean.yaml23
-rw-r--r--qtip/driver/playbook/dpi/dpi_average.sh10
-rw-r--r--qtip/driver/playbook/dpi/run.yaml42
-rw-r--r--qtip/driver/playbook/dpi/setup.yaml93
-rw-r--r--qtip/driver/playbook/inxi.yaml (renamed from qtip/driver/ansible/playbook/inxi.yaml)4
-rw-r--r--qtip/driver/playbook/openssl/clean.yaml23
-rw-r--r--qtip/driver/playbook/openssl/run.yaml45
-rw-r--r--qtip/driver/playbook/openssl/setup.yaml87
-rw-r--r--qtip/driver/playbook/prepare_env.yaml (renamed from qtip/driver/ansible/playbook/prepare_env.yaml)14
-rw-r--r--qtip/driver/playbook/ramspeed/clean.yaml23
-rw-r--r--qtip/driver/playbook/ramspeed/run.yaml40
-rw-r--r--qtip/driver/playbook/ramspeed/setup.yaml70
-rw-r--r--qtip/driver/playbook/top.yaml (renamed from qtip/driver/ansible/playbook/top.yaml)4
-rw-r--r--qtip/driver/playbook/unixbench/clean.yaml25
-rw-r--r--qtip/driver/playbook/unixbench/dhrystone.yaml41
-rw-r--r--qtip/driver/playbook/unixbench/run.yaml23
-rw-r--r--qtip/driver/playbook/unixbench/setup.yaml65
-rw-r--r--qtip/driver/playbook/unixbench/whetstone.yaml41
-rw-r--r--qtip/loader/file.py7
-rw-r--r--qtip/reporter/console.py46
-rw-r--r--qtip/reporter/templates/base.j225
-rw-r--r--qtip/reporter/templates/dpi.j25
-rw-r--r--qtip/reporter/templates/ramspeed.j213
-rw-r--r--qtip/reporter/templates/ssl.j221
-rw-r--r--qtip/reporter/templates/timeline.j2 (renamed from qtip/reporter/console/timeline.j2)6
-rw-r--r--qtip/reporter/templates/unixbench.j210
-rw-r--r--qtip/runner/__init__.py43
-rw-r--r--qtip/runner/base.py (renamed from qtip/reporter/base.py)6
-rw-r--r--qtip/runner/runner.py107
-rwxr-xr-xqtip/scripts/cleanup_creds.sh20
-rwxr-xr-xqtip/scripts/generate_host_file.sh (renamed from qtip/scripts/fetch_compute_ips.sh)39
-rwxr-xr-xqtip/scripts/qtip_creds.sh24
-rw-r--r--qtip/util/env.py288
-rw-r--r--requirements.txt2
-rw-r--r--setup.cfg6
-rw-r--r--test-requirements.txt1
-rw-r--r--tests/data/benchmarks/plan/compute.yaml74
-rw-r--r--tests/data/benchmarks/plan/sample.yaml (renamed from qtip/driver/ansible/ansible.py)14
-rw-r--r--tests/data/external/dpi/dpi_dump.txt809
-rw-r--r--tests/data/external/ramspeed/Floatmem52
-rw-r--r--tests/data/external/ramspeed/Intmem52
-rw-r--r--tests/data/external/ssl/AES-128-CBC_dump7
-rw-r--r--tests/data/external/ssl/RSA_dump9
-rw-r--r--tests/unit/api/conftest.py22
-rw-r--r--tests/unit/api/metric_controller_test.py37
-rw-r--r--tests/unit/api/plan_controller_test.py49
-rw-r--r--tests/unit/api/qpi_controller_test.py43
-rw-r--r--tests/unit/cli/cmd_metric_test.py14
-rw-r--r--tests/unit/cli/cmd_plan_test.py9
-rw-r--r--tests/unit/cli/cmd_qpi_test.py11
-rw-r--r--tests/unit/cli/cmd_report_test.py91
-rw-r--r--tests/unit/cli/options_test.py9
-rw-r--r--tests/unit/collector/collector_test.py (renamed from tests/unit/collector/base_test.py)0
-rw-r--r--tests/unit/loader/plan_test.py17
-rw-r--r--tests/unit/reporter/console_test.py89
-rw-r--r--tests/unit/runner/runner_test.py (renamed from qtip/reporter/console/__init__.py)7
-rw-r--r--tests/unit/util/env_test.py307
-rw-r--r--tests/unit/util/logger_test.py9
-rw-r--r--third-party/License/.gitrepo6
-rw-r--r--third-party/License/README.md5
121 files changed, 4565 insertions, 309 deletions
diff --git a/DEVELOP.md b/DEVELOP.md
index 893efca4..8e9545e6 100644
--- a/DEVELOP.md
+++ b/DEVELOP.md
@@ -46,6 +46,63 @@ It is for macOS uses TLS instead of OpenSSL and no header files supported. The s
# export LDFLAGS='-L $openssl_install_path/lib'
```
+### Third Party Code
+
+QTIP includes a few third party code via [subrepo](https://github.com/ingydotnet/git-subrepo).
+All third party code are stored in `/third-party`.
+
+To pull the changes from remote repository, use
+
+```
+git subrepo pull third-party/<subdir>
+```
+
+It will create a new commit in parent repo, i.e. `qtip`. However, the
+auto generated commit message does not include mandatory tags such as
+`Change-Id` required by gerrit. You need to manually amend the commit to
+append those.
+
+```
+git commit --amend -s
+```
+
+Example of final commit message
+
+```
+Include third party script for license checking and amending
+The following commit message are generated automatically by git-subrepo
+-----------------------------------------------------------------------------
+git subrepo clone git@github.com:openzero-zte/License.git third-party/License
+
+subrepo:
+ subdir: "third-party/License"
+ merged: "61489da"
+upstream:
+ origin: "git@github.com:openzero-zte/License.git"
+ branch: "master"
+ commit: "61489da"
+git-subrepo:
+ version: "0.3.0"
+ origin: "https://github.com/ingydotnet/git-subrepo"
+ commit: "988f8c8"
+-----------------------------------------------------------------------------
+Change-Id: I8eab86a8ce3f26995af3e3535f31f361b4826a8b
+Signed-off-by: Yujun Zhang <zhang.yujunz@zte.com.cn>
+```
+
+Sometimes you may modify the third-party code to adapt it in `qtip`.
+To push the changes to remote repository, run
+
+```
+git subrepo push third-party/<subdir>
+```
+
+If you want to include a new repository of third party code. Use
+
+```
+git subrepo clone <remote-url> [<subdir>]
+```
+
## Architecture
**TODO**: move to design spec
@@ -94,7 +151,23 @@ TBD
### CLI
-TBD
+Click currently supports Bash completion. The prerequisite for this is that the program
+needs to be installed correctly. To install Qtip, execute the following command in root
+folder of Qtip:
+
+```
+cd <project root>
+pip install -e .
+```
+
+Once the installation has been completed successfully, the following needs to be added to
+the `.bashrc` file:
+
+```
+eval "$(_QTIP_COMPLETE=source qtip)"
+```
+
+The above would activate command completion for Qtip.
### API
diff --git a/benchmarks/QPI/compute.yaml b/benchmarks/QPI/compute.yaml
new file mode 100644
index 00000000..78a2d324
--- /dev/null
+++ b/benchmarks/QPI/compute.yaml
@@ -0,0 +1,37 @@
+##############################################################################
+# Copyright (c) 2016 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
+##############################################################################
+title: compute
+description: sample performance index of computing
+formula: weighted arithmetic mean
+sections:
+- name: Integer
+ weight: 0.3
+ formula: geometric mean
+ metrics:
+ - dhrystone.yaml
+- name: Float
+ weight: 0.3
+ formula: geometric mean
+ metrics:
+ - whetstone.yaml
+- name: Memory
+ weight: 0.2
+ formula: geometric mean
+ metrics:
+ - ramspeed.yaml
+- name: DPI
+ weight: 0.1
+ formula: geometric mean
+ metrics:
+ - dpi.yaml
+- name: SSL
+ weight: 0.1
+ formula: geometric mean
+ metrics:
+ - ssl.yaml
diff --git a/benchmarks/metric/dhrystone.yaml b/benchmarks/metric/dhrystone.yaml
new file mode 100644
index 00000000..e4d26248
--- /dev/null
+++ b/benchmarks/metric/dhrystone.yaml
@@ -0,0 +1,17 @@
+##############################################################################
+# Copyright (c) 2016 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: dhrystone
+description: >
+ A synthetic computing benchmark program intended to be representative of
+ system (integer) programming.
+links:
+ - https://en.wikipedia.org/wiki/Dhrystone
+workloads:
+ - single_cpu
+ - multi_cpu
diff --git a/qtip/driver/sample.py b/benchmarks/metric/dpi.yaml
index 9b347949..c90075d2 100644
--- a/qtip/driver/sample.py
+++ b/benchmarks/metric/dpi.yaml
@@ -1,15 +1,13 @@
##############################################################################
-# Copyright (c) 2016 ZTE Corp and others.
+# Copyright (c) 2016 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
##############################################################################
-
-
-from base import BaseDriver
-
-
-class SampleDriver(BaseDriver):
- """sample driver that generates random data for testing"""
+name: dpi
+description: deep packet inspection
+workloads:
+ - bps
+ - pps
diff --git a/benchmarks/metric/ramspeed.yaml b/benchmarks/metric/ramspeed.yaml
new file mode 100644
index 00000000..e2e2b98f
--- /dev/null
+++ b/benchmarks/metric/ramspeed.yaml
@@ -0,0 +1,13 @@
+##############################################################################
+# Copyright (c) 2016 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: ramspeed
+description: a memory performance benchmarking
+workloads:
+ - int: [add, average, copy, scale, triad]
+ - float: [add, average, copy, scale, triad]
diff --git a/benchmarks/metric/ssl.yaml b/benchmarks/metric/ssl.yaml
new file mode 100644
index 00000000..2b01dccd
--- /dev/null
+++ b/benchmarks/metric/ssl.yaml
@@ -0,0 +1,13 @@
+##############################################################################
+# Copyright (c) 2016 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: ssl
+description: a Secure Sockets Layer performance benchmarking
+workloads:
+ - aes_128_cbc: [512, 1024, 2048, 4096]
+ - rsa_sig: [16, 64, 256, 1024, 8192]
diff --git a/benchmarks/metric/whetstone.yaml b/benchmarks/metric/whetstone.yaml
new file mode 100644
index 00000000..625ea87f
--- /dev/null
+++ b/benchmarks/metric/whetstone.yaml
@@ -0,0 +1,18 @@
+##############################################################################
+# Copyright (c) 2016 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: whetstone
+description: >
+ A synthetic benchmark for evaluating the performance of computers.
+ The Whetstone benchmark primarily measures the floating-point arithmetic
+ performance.
+links:
+ - https://en.wikipedia.org/wiki/Whetstone_(benchmark)
+workloads:
+ - single_cpu
+ - multi_cpu
diff --git a/benchmarks/plan/compute.yaml b/benchmarks/plan/compute.yaml
new file mode 100644
index 00000000..f4a7a2dc
--- /dev/null
+++ b/benchmarks/plan/compute.yaml
@@ -0,0 +1,120 @@
+##############################################################################
+# 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: compute QPI
+description: compute QPI profile
+info:
+ facility: local
+ engineer: local
+config:
+ driver: ansible
+ collectors:
+ - type: logfile
+ paths:
+ - '../../external/dpi/'
+ logs:
+ - filename: dpi_dump.txt
+ parsers:
+ - type: grep
+ regex: |-
+ ^\s+nDPI throughput:.+?(?P<pps>\d+.\d+)\sM\spps.+
+ ?(?P<bps>\d+.\d+)\sGb\/sec
+ - type: logfile
+ paths:
+ - '../../external/ramspeed/'
+ logs:
+ - filename: Intmem
+ parsers:
+ - type: grep
+ regex: '^INTEGER\s+BatchRun\s+Copy:\s+?(?P<integer_copy>\d+\.\d+)\sMB/s$'
+ - type: grep
+ regex: '^INTEGER\s+BatchRun\s+Scale:\s+?(?P<integer_scale>\d+\.\d+)\sMB/s$'
+ - type: grep
+ regex: '^INTEGER\s+BatchRun\s+Add:\s+?(?P<integer_add>\d+\.\d+)\sMB/s$'
+ - type: grep
+ regex: '^INTEGER\s+BatchRun\s+Triad:\s+?(?P<integer_triad>\d+\.\d+)\sMB/s$'
+ - type: grep
+ regex: '^INTEGER\s+BatchRun\s+AVERAGE:\s+?(?P<integer_average>\d+\.\d+)\sMB/s$'
+ - filename: Floatmem
+ parsers:
+ - type: grep
+ regex: '^FL-POINT\s+BatchRun\s+Copy:\s+?(?P<float_copy>\d+\.\d+)\sMB/s$'
+ - type: grep
+ regex: '^FL-POINT\s+BatchRun\s+Scale:\s+?(?P<float_scale>\d+\.\d+)\sMB/s$'
+ - type: grep
+ regex: '^FL-POINT\s+BatchRun\s+Add:\s+?(?P<float_add>\d+\.\d+)\sMB/s$'
+ - type: grep
+ regex: '^FL-POINT\s+BatchRun\s+Triad:\s+?(?P<float_triad>\d+\.\d+)\sMB/s$'
+ - type: grep
+ regex: '^FL-POINT\s+BatchRun\s+AVERAGE:\s+?(?P<float_average>\d+\.\d+)\sMB/s$'
+ - type: logfile
+ paths:
+ - '../../external/ssl/'
+ logs:
+ - filename: RSA_dump
+ parsers:
+ - type: grep
+ regex: |-
+ ^rsa\s+512\sbits\s.+
+ ?(?P<rsa_sign_512>\d+\.\d)\s+
+ ?(?P<rsa_verify_512>\d+\.\d)$
+ - type: grep
+ regex: |-
+ ^rsa\s+1024\sbits\s.+
+ ?(?P<rsa_sign_1024>\d+\.\d)\s+
+ ?(?P<rsa_verify_1024>\d+\.\d)$
+ - type: grep
+ regex: |-
+ ^rsa\s+2048\sbits\s.+
+ ?(?P<rsa_sign_2048>\d+\.\d)\s+
+ ?(?P<rsa_verify_2048>\d+\.\d)$
+ - type: grep
+ regex: |-
+ ^rsa\s+4096\sbits\s.+
+ ?(?P<rsa_sign_4096>\d+\.\d)\s+
+ ?(?P<rsa_verify_4096>\d+\.\d)$
+ - filename: AES-128-CBC_dump
+ parsers:
+ - type: grep
+ regex: |-
+ ^aes-128-cbc\s+
+ ?(?P<aes_128_cbc_16_bytes>\d+\.\w+)\s+
+ ?(?P<aes_128_cbc_64_bytes>\d+\.\w+)\s+
+ ?(?P<aes_128_cbc_256_bytes>\d+\.\w+)\s+
+ ?(?P<aes_128_cbc_1024_bytes>\d+\.\w+)\s+
+ ?(?P<aes_128_cbc_8192_bytes>\d+\.\w+)$
+ - type: logfile
+ paths:
+ - '../../external/sysinfo'
+ logs:
+ - filename: top.log
+ parsers:
+ - type: grep
+ regex: 'Cpu\(s\):.+?(?P<cpu_idle>\d+\.\d)\sid'
+ - filename: inxi.log
+ parsers:
+ - type: grep
+ regex: '.+\s+Host:\s+(?P<hostname>.+)\sKernel'
+ - type: grep
+ regex: '.+\sMemory:\s+(?P<memory>.+MB)\s'
+ - type: grep
+ regex: '^CPU\(s\):\s+(?P<cpu>.+)'
+ - type: grep
+ regex: '.+\sDistro:\s+(?P<os>.+)'
+ - type: grep
+ regex: '.+\sKernel:\s+(?P<kernel>.+)\sConsole'
+ - type: grep
+ regex: '.+\s+HDD Total Size:\s+(?P<disk>.+)\s'
+ - type: grep
+ regex: '.+\sproduct:\s+(?P<product>.+)\sversion'
+ reporter:
+ name: console
+ # transform collected data into timeline
+ transformer: timeline
+QPIs:
+ - compute.yaml
diff --git a/qtip/driver/yardstick.py b/benchmarks/plan/sample.yaml
index 83f1b3d8..04e8caf9 100644
--- a/qtip/driver/yardstick.py
+++ b/benchmarks/plan/sample.yaml
@@ -1,14 +1,14 @@
##############################################################################
-# Copyright (c) 2016 ZTE Corp and others.
+# 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
##############################################################################
-
-from base import BaseDriver
-
-
-class YardstickDriver(BaseDriver):
- """driver for running performance test with yardstick"""
+name: sample
+description: sample benchmark plan for testing default path
+config:
+ collectors: []
+ reporters: []
+QPIs: []
diff --git a/collector/2017-03-16-20-07/result.json b/collector/2017-03-16-20-07/result.json
new file mode 100644
index 00000000..d26ad400
--- /dev/null
+++ b/collector/2017-03-16-20-07/result.json
@@ -0,0 +1,265 @@
+{
+ "plan_name": "compute_qpi",
+ "start_time": "2017-03-11-03-14",
+ "stop_time": "2017-03-11-03-32",
+ "sut": [
+ {
+ "name": "node-41",
+ "qpis": [
+ {
+ "benchmarks": [
+ {
+ "name": "ssl",
+ "cpu_usage": "3%",
+ "results": {
+ "aes_128_cbc_1024_bytes": "584709.80k",
+ "aes_128_cbc_16_bytes": "531050.51k",
+ "aes_128_cbc_256_bytes": "584951.30k",
+ "aes_128_cbc_64_bytes": "571063.66k",
+ "aes_128_cbc_8192_bytes": "584723.11k",
+ "rsa_sign_1024": "2.6",
+ "rsa_sign_2048": "9.9",
+ "rsa_sign_4096": "1.7",
+ "rsa_sign_512": "0.5",
+ "rsa_verify_1024": "101616.4",
+ "rsa_verify_2048": "31104.1",
+ "rsa_verify_4096": "7688.5",
+ "rsa_verify_512": "257411.2"
+ },
+ "sysinfo": {
+ "cpu": "2 Deca core Intel Xeon E5-2650 v3s (-HT-MCP-SMP-) speed/max: 1199/3000 MHz",
+ "disk": "1200.3GB (1.0% used)",
+ "hostname": "node-41.zte.com.cn",
+ "kernel": "4.4.0-62-generic x86_64 (64 bit)",
+ "memory": "4449.9/128524.1MB",
+ "os": "Ubuntu 16.04 xenial",
+ "product": "EC600G3"
+ }
+ },
+ {
+ "name": "ramspeed",
+ "cpu_usage": "3%",
+ "results": {
+ "float_add": "10217.62",
+ "float_average": "9176.88",
+ "float_copy": "8127.13",
+ "float_scale": "8085.40",
+ "float_triad": "10277.38",
+ "integer_add": "11471.63",
+ "integer_average": "11396.35",
+ "integer_copy": "11297.18",
+ "integer_scale": "11316.86",
+ "integer_triad": "11499.74"
+ },
+ "sysinfo": {
+ "cpu": "2 Deca core Intel Xeon E5-2650 v3s (-HT-MCP-SMP-) speed/max: 1200/3000 MHz",
+ "disk": "1200.3GB (1.0% used)",
+ "hostname": "node-41.zte.com.cn",
+ "kernel": "4.4.0-62-generic x86_64 (64 bit)",
+ "memory": "4388.3/128524.1MB",
+ "os": "Ubuntu 16.04 xenial",
+ "product": "EC600G3"
+ }
+ },
+ {
+ "name": "whetstone",
+ "cpu_usage": "3%",
+ "results": {
+ "multi_cpus": {
+ "num": "40",
+ "score": "21198.3"
+ },
+ "single_cpu": {
+ "num": "1",
+ "score": "633.2"
+ },
+ "total_cpus": "40"
+ },
+ "sysinfo": {
+ "cpu": "2 Deca core Intel Xeon E5-2650 v3s (-HT-MCP-SMP-) speed/max: 1393/3000 MHz",
+ "disk": "1200.3GB (1.0% used)",
+ "hostname": "node-41.zte.com.cn",
+ "kernel": "4.4.0-62-generic x86_64 (64 bit)",
+ "memory": "4390.1/128524.1MB",
+ "os": "Ubuntu 16.04 xenial",
+ "product": "EC600G3"
+ }
+ },
+ {
+ "name": "dpi",
+ "cpu_usage": "3%",
+ "results": {
+ "bps": 3.638,
+ "pps": 1.45
+ },
+ "sysinfo": {
+ "cpu": "2 Deca core Intel Xeon E5-2650 v3s (-HT-MCP-SMP-) speed/max: 1199/3000 MHz",
+ "disk": "1200.3GB (1.0% used)",
+ "hostname": "node-41.zte.com.cn",
+ "kernel": "4.4.0-62-generic x86_64 (64 bit)",
+ "memory": "4409.8/128524.1MB",
+ "os": "Ubuntu 16.04 xenial",
+ "product": "EC600G3"
+ }
+ },
+ {
+ "name": "dhrystone",
+ "cpu_usage": "3%",
+ "results": {
+ "multi_cpus": {
+ "num": "40",
+ "score": "63529.6"
+ },
+ "single_cpu": {
+ "num": "1",
+ "score": "2981.5"
+ },
+ "total_cpus": "40"
+ },
+ "sysinfo": {
+ "cpu": "2 Deca core Intel Xeon E5-2650 v3s (-HT-MCP-SMP-) speed/max: 1199/3000 MHz",
+ "disk": "1200.3GB (1.0% used)",
+ "hostname": "node-41.zte.com.cn",
+ "kernel": "4.4.0-62-generic x86_64 (64 bit)",
+ "memory": "4390.9/128524.1MB",
+ "os": "Ubuntu 16.04 xenial",
+ "product": "EC600G3"
+ }
+ }
+ ],
+ "name": "compute_qpi"
+ }
+ ],
+ "type": "baremetal"
+ },
+ {
+ "name": "node-38",
+ "qpis": [
+ {
+ "benchmarks": [
+ {
+ "name": "ssl",
+ "cpu_usage": "3%",
+ "results": {
+ "aes_128_cbc_1024_bytes": "654325.42k",
+ "aes_128_cbc_16_bytes": "602261.15k",
+ "aes_128_cbc_256_bytes": "663959.64k",
+ "aes_128_cbc_64_bytes": "650967.68k",
+ "aes_128_cbc_8192_bytes": "667303.94k",
+ "rsa_sign_1024": "6.8",
+ "rsa_sign_2048": "8.8",
+ "rsa_sign_4096": "7.1",
+ "rsa_sign_512": "8.5",
+ "rsa_verify_1024": "100088.3",
+ "rsa_verify_2048": "31316.4",
+ "rsa_verify_4096": "8551.8",
+ "rsa_verify_512": "252476.3"
+ },
+ "sysinfo": {
+ "cpu": "2 Deca core Intel Xeon E5-2650 v3s (-HT-MCP-SMP-) speed/max: 1199/3000 MHz",
+ "disk": "1200.3GB (1.0% used)",
+ "hostname": "node-38.zte.com.cn",
+ "kernel": "4.4.0-62-generic x86_64 (64 bit)",
+ "memory": "4403.7/128524.1MB",
+ "os": "Ubuntu 16.04 xenial",
+ "product": "EC600G3"
+ }
+ },
+ {
+ "name": "ramspeed",
+ "cpu_usage": "3%",
+ "results": {
+ "float_add": "10522.33",
+ "float_average": "9465.11",
+ "float_copy": "8434.94",
+ "float_scale": "8436.36",
+ "float_triad": "10466.82",
+ "integer_add": "11489.06",
+ "integer_average": "11466.52",
+ "integer_copy": "11398.52",
+ "integer_scale": "11413.87",
+ "integer_triad": "11564.61"
+ },
+ "sysinfo": {
+ "cpu": "2 Deca core Intel Xeon E5-2650 v3s (-HT-MCP-SMP-) speed/max: 1200/3000 MHz",
+ "disk": "1200.3GB (1.0% used)",
+ "hostname": "node-38.zte.com.cn",
+ "kernel": "4.4.0-62-generic x86_64 (64 bit)",
+ "memory": "4402.9/128524.1MB",
+ "os": "Ubuntu 16.04 xenial",
+ "product": "EC600G3"
+ }
+ },
+ {
+ "name": "whetstone",
+ "cpu_usage": "3%",
+ "results": {
+ "multi_cpus": {
+ "num": "40",
+ "score": "21194.7"
+ },
+ "single_cpu": {
+ "num": "1",
+ "score": "676.6"
+ },
+ "total_cpus": "40"
+ },
+ "sysinfo": {
+ "cpu": "2 Deca core Intel Xeon E5-2650 v3s (-HT-MCP-SMP-) speed/max: 1200/3000 MHz",
+ "disk": "1200.3GB (1.0% used)",
+ "hostname": "node-38.zte.com.cn",
+ "kernel": "4.4.0-62-generic x86_64 (64 bit)",
+ "memory": "4405.5/128524.1MB",
+ "os": "Ubuntu 16.04 xenial",
+ "product": "EC600G3"
+ }
+ },
+ {
+ "name": "dpi",
+ "cpu_usage": "3%",
+ "results": {
+ "bps": 3.69,
+ "pps": 1.458
+ },
+ "sysinfo": {
+ "cpu": "2 Deca core Intel Xeon E5-2650 v3s (-HT-MCP-SMP-) speed/max: 1200/3000 MHz",
+ "disk": "1200.3GB (1.0% used)",
+ "hostname": "node-38.zte.com.cn",
+ "kernel": "4.4.0-62-generic x86_64 (64 bit)",
+ "memory": "4418.2/128524.1MB",
+ "os": "Ubuntu 16.04 xenial",
+ "product": "EC600G3"
+ }
+ },
+ {
+ "name": "dhrystone",
+ "cpu_usage": "3%",
+ "results": {
+ "multi_cpus": {
+ "num": "40",
+ "score": "63834.1"
+ },
+ "single_cpu": {
+ "num": "1",
+ "score": "3026.2"
+ },
+ "total_cpus": "40"
+ },
+ "sysinfo": {
+ "cpu": "2 Deca core Intel Xeon E5-2650 v3s (-HT-MCP-SMP-) speed/max: 1200/3000 MHz",
+ "disk": "1200.3GB (1.0% used)",
+ "hostname": "node-38.zte.com.cn",
+ "kernel": "4.4.0-62-generic x86_64 (64 bit)",
+ "memory": "4404.9/128524.1MB",
+ "os": "Ubuntu 16.04 xenial",
+ "product": "EC600G3"
+ }
+ }
+ ],
+ "name": "compute_qpi"
+ }
+ ],
+ "type": "baremetal"
+ }
+ ]
+}
diff --git a/collector/timeline.json b/collector/timeline.json
new file mode 100644
index 00000000..dea929e7
--- /dev/null
+++ b/collector/timeline.json
@@ -0,0 +1,39 @@
+{
+ "phases": [{
+ "name": "Monitor",
+ "checkpoints": [{
+ "name": "T00",
+ "timestamp": "1"
+ }]
+ }, {
+ "name": "Inspector",
+ "checkpoints": [{
+ "name": "T01",
+ "timestamp": "2"
+ }, {
+ "name": "T02 ",
+ "timestamp": "5"
+ }, {
+ "name": "T03 ",
+ "timestamp": "8"
+ }]
+ }, {
+ "name": "Controller",
+ "checkpoints": [{
+ "name": "T04",
+ "timestamp": "11"
+ }]
+ }, {
+ "name": "Notifier",
+ "checkpoints": [{
+ "name": "T05 ",
+ "timestamp": "16"
+ }]
+ }, {
+ "name": "Evaluator",
+ "checkpoints": [{
+ "name": "T06 ",
+ "timestamp": "40"
+ }]
+ }]
+}
diff --git a/docker/Dockerfile b/docker/Dockerfile
index f2a543e6..d609273d 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -22,6 +22,9 @@ RUN apt-get update && apt-get install -y \
gcc \
ssh \
expect \
+ build-essential\
+ libssl-dev\
+ libffi-dev\
python-matplotlib \
python-dev \
python-pip \
@@ -32,6 +35,8 @@ RUN apt-get update && apt-get install -y \
curl \
supervisor \
python-setuptools \
+ iputils-ping\
+ rsync \
--no-install-recommends \
&& rm -rf /var/lib/apt/lists/*
@@ -50,14 +55,14 @@ RUN mkdir -p $HOME/qtip/results
RUN chmod 700 /root/.ssh
#Config ansible
-COPY ansible.cfg.default /root/.ansible.cfg
+COPY ansible.cfg.default $HOME/.ansible.cfg
#Cloning Repos
RUN git config --global http.sslVerify false
RUN git clone -b $BRANCH https://gerrit.opnfv.org/gerrit/qtip $REPOS_DIR/qtip
RUN git clone https://gerrit.opnfv.org/gerrit/releng $REPOS_DIR/releng
-RUN pip install -r $REPOS_DIR/qtip/requirements.txt
+RUN pip install -U -r $REPOS_DIR/qtip/requirements.txt
#Config supervisor
RUN mkdir -p /var/log/supervisor
diff --git a/docker/Dockerfile.aarch64.patch b/docker/Dockerfile.aarch64.patch
new file mode 100644
index 00000000..80529476
--- /dev/null
+++ b/docker/Dockerfile.aarch64.patch
@@ -0,0 +1,33 @@
+From: Cristina Pauna <cristina.pauna@enea.com>
+Date: Mon, 13 Mar 2017 11:56:59 +0200
+Subject: [PATCH] Modify Dockerfile to build an aarch64 image
+
+This patch adapts the Dockerfile so that the qtip image
+can be build on an aarch64 machine
+
+Signed-off-by: Cristina Pauna <cristina.pauna@enea.com>
+---
+ docker/Dockerfile | 14 ++++++--------
+ 1 file changed, 6 insertions(+), 8 deletions(-)
+
+diff --git a/docker/Dockerfile b/docker/Dockerfile
+index a4a7e47..5d4467b 100644
+--- a/docker/Dockerfile
++++ b/docker/Dockerfile
+@@ -1,10 +1,10 @@
+-##########################################
+-#####Docker container for QTIP############
+-##########################################
++###################################################
++##### AArch64 Docker container for QTIP############
++###################################################
+
+-FROM ubuntu:16.04
+-MAINTAINER Yujun Zhang <zhang.yujunz@zte.com.cn>
+-LABEL version="0.1" description="OPNFV QTIP Docker container"
++FROM aarch64/ubuntu:16.04
++MAINTAINER Armband team <armband@enea.com>
++LABEL version="0.1" description="OPNFV QTIP AArch64 Docker container"
+
+ ARG BRANCH=master
+
diff --git a/docs/release/release-notes/index.rst b/docs/release/release-notes/index.rst
index 5d045388..3864c451 100644
--- a/docs/release/release-notes/index.rst
+++ b/docs/release/release-notes/index.rst
@@ -1,3 +1,5 @@
+.. _qtip-releasenotes:
+
.. This work is licensed under a Creative Commons Attribution 4.0 International License.
.. http://creativecommons.org/licenses/by/4.0
.. (c) 2015 Dell Inc.
diff --git a/docs/development/design/apidocs/index.rst b/docs/testing/developer/design/apidocs/index.rst
index 241a2680..241a2680 100644
--- a/docs/development/design/apidocs/index.rst
+++ b/docs/testing/developer/design/apidocs/index.rst
diff --git a/docs/development/design/apidocs/qtip_restful_api.rst b/docs/testing/developer/design/apidocs/qtip_restful_api.rst
index 06c01292..06c01292 100644
--- a/docs/development/design/apidocs/qtip_restful_api.rst
+++ b/docs/testing/developer/design/apidocs/qtip_restful_api.rst
diff --git a/docs/testing/developer/design/cli.rst b/docs/testing/developer/design/cli.rst
new file mode 100644
index 00000000..72d1fbaf
--- /dev/null
+++ b/docs/testing/developer/design/cli.rst
@@ -0,0 +1,92 @@
+***************************
+QTIP Command Line Interface
+***************************
+
+Abstract
+########
+
+QTIP consists of different tools(metrics) to benchmark the NFVI. These metrics fall under different NFVI
+subsystems(QPI's) such as compute, storage and network. A plan consists of one or more QPI's, depending upon how
+the end user would want to measure performance. CLI is designed to help the user, execute benchmarks and
+view respective scores.
+
+Framework
+=========
+
+QTIP CLI has been created using the Python package `Click`_, Command Line Interface Creation Kit. It has been
+chosen for number of reasons. It presents the user with a very simple yet powerful API to build complex
+applications. One of the most striking features is command nesting.
+
+As explained, QTIP consists of metrics, QPI's and plans. CLI is designed to provide interface to all
+these components. It is responsible for execution, as well as provide listing and details of each individual
+element making up these components.
+
+Design
+======
+
+CLI's entry point extends Click's built in MultiCommand class object. It provides two methods, which are
+overridden to provide custom configurations.
+
+.. code-block:: python
+
+ class QtipCli(click.MultiCommand):
+
+ def list_commands(self, ctx):
+ rv = []
+ for filename in os.listdir(cmd_folder):
+ if filename.endswith('.py') and \
+ filename.startswith('cmd_'):
+ rv.append(filename[4:-3])
+ rv.sort()
+ return rv
+
+ def get_command(self, ctx, name):
+ try:
+ if sys.version_info[0] == 2:
+ name = name.encode('ascii', 'replace')
+ mod = __import__('qtip.cli.commands.cmd_' + name,
+ None, None, ['cli'])
+ except ImportError:
+ return
+ return mod.cli
+
+Commands and subcommands will then be loaded by the ``get_command`` method above.
+
+Extending the Framework
+=======================
+
+Framework can be easily extended, as per the users requirements. One such example can be to override the builtin
+configurations with user defined ones. These can be written in a file, loaded via a Click Context and passed
+through to all the commands.
+
+.. code-block:: python
+
+ class Context:
+
+ def __init__():
+
+ self.config = ConfigParser.ConfigParser()
+ self.config.read('path/to/configuration_file')
+
+ def get_paths():
+
+ paths = self.config.get('section', 'path')
+ return paths
+
+The above example loads configuration from user defined paths, which then need to be provided to the actual
+command definitions.
+
+.. code-block:: python
+
+ from qtip.cli.entry import Context
+
+ pass_context = click.make_pass_decorator(Context, ensure=False)
+
+ @cli.command('list', help='List the Plans')
+ @pass_context
+ def list(ctx):
+ plans = Plan.list_all(ctx.paths())
+ table = utils.table('Plans', plans)
+ click.echo(table)
+
+.. _Click: http://click.pocoo.org/5/
diff --git a/docs/development/design/compute_QPI.rst b/docs/testing/developer/design/compute_QPI.rst
index 2e5aa87c..2e5aa87c 100644
--- a/docs/development/design/compute_QPI.rst
+++ b/docs/testing/developer/design/compute_QPI.rst
diff --git a/docs/development/design/dashboard.rst b/docs/testing/developer/design/dashboard.rst
index 60c4720d..60c4720d 100644
--- a/docs/development/design/dashboard.rst
+++ b/docs/testing/developer/design/dashboard.rst
diff --git a/docs/development/design/index.rst b/docs/testing/developer/design/index.rst
index b6dd0c01..b6dd0c01 100644
--- a/docs/development/design/index.rst
+++ b/docs/testing/developer/design/index.rst
diff --git a/docs/development/design/integration_with_yardstick.rst b/docs/testing/developer/design/integration_with_yardstick.rst
index a8298d6f..a8298d6f 100644
--- a/docs/development/design/integration_with_yardstick.rst
+++ b/docs/testing/developer/design/integration_with_yardstick.rst
diff --git a/docs/development/overview/.gitkeep b/docs/testing/developer/overview/.gitkeep
index e69de29b..e69de29b 100644
--- a/docs/development/overview/.gitkeep
+++ b/docs/testing/developer/overview/.gitkeep
diff --git a/docs/development/requirement/.gitkeep b/docs/testing/developer/requirement/.gitkeep
index e69de29b..e69de29b 100644
--- a/docs/development/requirement/.gitkeep
+++ b/docs/testing/developer/requirement/.gitkeep
diff --git a/docs/release/installation/.gitkeep b/docs/testing/user/.gitkeep
index e69de29b..e69de29b 100644
--- a/docs/release/installation/.gitkeep
+++ b/docs/testing/user/.gitkeep
diff --git a/docs/release/configguide/configuration.rst b/docs/testing/user/configguide/configuration.rst
index 78e96492..78e96492 100644
--- a/docs/release/configguide/configuration.rst
+++ b/docs/testing/user/configguide/configuration.rst
diff --git a/docs/release/configguide/index.rst b/docs/testing/user/configguide/index.rst
index d5e05d63..d5e05d63 100644
--- a/docs/release/configguide/index.rst
+++ b/docs/testing/user/configguide/index.rst
diff --git a/docs/release/scenarios/.gitkeep b/docs/testing/user/installation/.gitkeep
index e69de29b..e69de29b 100644
--- a/docs/release/scenarios/.gitkeep
+++ b/docs/testing/user/installation/.gitkeep
diff --git a/qtip/driver/ansible/__init__.py b/docs/testing/user/scenarios/.gitkeep
index e69de29b..e69de29b 100644
--- a/qtip/driver/ansible/__init__.py
+++ b/docs/testing/user/scenarios/.gitkeep
diff --git a/docs/release/userguide/_01-compute.rst b/docs/testing/user/userguide/_01-compute.rst
index 56be5488..56be5488 100644
--- a/docs/release/userguide/_01-compute.rst
+++ b/docs/testing/user/userguide/_01-compute.rst
diff --git a/docs/release/userguide/_02-network.rst b/docs/testing/user/userguide/_02-network.rst
index 00fe5b0a..00fe5b0a 100644
--- a/docs/release/userguide/_02-network.rst
+++ b/docs/testing/user/userguide/_02-network.rst
diff --git a/docs/release/userguide/_03-storage.rst b/docs/testing/user/userguide/_03-storage.rst
index b1490432..b1490432 100644
--- a/docs/release/userguide/_03-storage.rst
+++ b/docs/testing/user/userguide/_03-storage.rst
diff --git a/docs/release/userguide/_testcase_description.rst b/docs/testing/user/userguide/_testcase_description.rst
index d60ca949..d60ca949 100644
--- a/docs/release/userguide/_testcase_description.rst
+++ b/docs/testing/user/userguide/_testcase_description.rst
diff --git a/docs/release/userguide/annex.rst b/docs/testing/user/userguide/annex.rst
index e8bf5555..e8bf5555 100644
--- a/docs/release/userguide/annex.rst
+++ b/docs/testing/user/userguide/annex.rst
diff --git a/docs/release/userguide/benchmark-suites.rst b/docs/testing/user/userguide/benchmark-suites.rst
index 84d1c647..84d1c647 100644
--- a/docs/release/userguide/benchmark-suites.rst
+++ b/docs/testing/user/userguide/benchmark-suites.rst
diff --git a/docs/testing/user/userguide/cli.rst b/docs/testing/user/userguide/cli.rst
new file mode 100644
index 00000000..e18a36f9
--- /dev/null
+++ b/docs/testing/user/userguide/cli.rst
@@ -0,0 +1,38 @@
+**************
+QTIP CLI Usage
+**************
+
+QTIP consists of a number of benchmarking tools or metrics, grouped under QPI's. QPI's map to the different
+components of a NFVI ecosystem, such as compute, network and storage. Depending on the type of application,
+a user may group them under plans.
+
+QTIP CLI provides interface to all of the above the components. A help page provides a list of all the commands
+along with a short description.
+::
+
+ qtip [-h|--help]
+
+Typically a complete plan is executed at the
+target environment. QTIP defaults to a number of sample plans. One may be able to list them using
+::
+
+ qtip plan list
+
+One can also be able to view the details about a specific plan.
+::
+
+ qtip plan show <plan_name>
+
+where *plan_name* is one of those listed from the previous command.
+
+To execute a complete plan
+::
+
+ qtip plan run <plan_name>
+
+Similarly, the same commands can be used for the other two components making up the plans, i.e QPI's and metrics.
+
+Debug option helps identify the error by providing a detailed traceback. It can be enabled as
+::
+
+ qtip [-d|--debug] plan run <plan_name>
diff --git a/docs/release/userguide/index.rst b/docs/testing/user/userguide/index.rst
index 4be3e498..4be3e498 100644
--- a/docs/release/userguide/index.rst
+++ b/docs/testing/user/userguide/index.rst
diff --git a/docs/release/userguide/introduction.rst b/docs/testing/user/userguide/introduction.rst
index 3147f0aa..3147f0aa 100644
--- a/docs/release/userguide/introduction.rst
+++ b/docs/testing/user/userguide/introduction.rst
diff --git a/legacy/assets/perftest/etc/dpi_average.sh b/legacy/assets/perftest/etc/dpi_average.sh
deleted file mode 100644
index 405d3ff6..00000000
--- a/legacy/assets/perftest/etc/dpi_average.sh
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/bin/bash
-
-COUNTER=0
-WDIR=$PWD
-while [ $COUNTER -lt 10 ]; do
-
- echo $WDIR
- $( ./ndpiReader -i test.pcap >> $WDIR/dpi_dump.txt )
- let COUNTER=COUNTER+1
- echo "Run number: $COUNTER"
-
-done
-
-
diff --git a/opt/infra/roles/qtip/files/run_qtip_server.sh b/opt/infra/roles/qtip/files/run_qtip_server.sh
index 0f5cafea..75145e2b 100644
--- a/opt/infra/roles/qtip/files/run_qtip_server.sh
+++ b/opt/infra/roles/qtip/files/run_qtip_server.sh
@@ -1,4 +1,24 @@
#!/bin/bash
envs="INSTALLER_TYPE=fuel -e INSTALLER_IP=10.20.0.2 -e NODE_NAME=zte-pod1"
-docker run --name qtip -id -e $envs -p 5000:5000 opnfv/qtip
+
+# use ramfs to fix docker socket connection issue with overlay mode in centos
+ramfs=/tmp/qtip/ramfs
+if [ ! -d $ramfs ]; then
+ mkdir -p $ramfs
+fi
+
+if [ ! -z $(df $ramfs | tail -n -1 | grep $ramfs) ]; then
+ sudo mount -t tmpfs -o size=32M tmpfs $ramfs
+fi
+
+# enable contro path in docker
+echo <<EOF > /tmp/ansible.cfg
+[defaults]
+callback_whitelist = profile_tasks
+[ssh_connection]
+control_path=/mnt/ramfs/ansible-ssh-%%h-%%p-%%r
+EOF
+
+docker run --name qtip -id -e $envs -p 5000:5000 -v $ramfs:/mnt/ramfs opnfv/qtip
+docker cp qtip /tmp/ansible.cfg /home/opnfv/.ansible.cfg
diff --git a/qtip/api/__main__.py b/qtip/api/__main__.py
index 89298e6d..381622af 100644
--- a/qtip/api/__main__.py
+++ b/qtip/api/__main__.py
@@ -1,10 +1,28 @@
+##############################################################################
+# 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 connexion
+import os
+
+
+swagger_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), 'swagger/'))
+
+
+def get_app():
+ app = connexion.App(__name__, specification_dir=swagger_dir)
+ app.add_api('swagger.yaml', base_path='/v1.0', strict_validation=True)
+ return app
def main():
- app = connexion.App(__name__, specification_dir='swagger/')
- app.add_api('swagger.yaml', base_path='/v1.0')
- app.run(host='0.0.0.0', port='5000')
+ app = get_app()
+ app.run(host="0.0.0.0", port=5000)
if __name__ == '__main__':
diff --git a/qtip/api/controllers/common.py b/qtip/api/controllers/common.py
new file mode 100644
index 00000000..6ddab7a9
--- /dev/null
+++ b/qtip/api/controllers/common.py
@@ -0,0 +1,35 @@
+##############################################################################
+# 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
+##############################################################################
+
+import httplib
+
+import connexion
+
+from qtip.base import error
+
+
+def check_endpoint_for_error(resource, operation=None):
+ def _decorator(func):
+ def _execute(name=None):
+ try:
+ return func(name), httplib.OK
+ except error.NotFoundError:
+ return connexion.problem(
+ httplib.NOT_FOUND,
+ '{} not found'.format(resource),
+ 'Requested {} `{}` not found.'
+ .format(resource.lower(), name))
+ except error.ToBeDoneError:
+ return connexion.problem(
+ httplib.NOT_IMPLEMENTED,
+ '{} handler not implemented'.format(operation),
+ 'Requested operation `{}` on {} not implemented.'
+ .format(operation.lower(), resource.lower()))
+ return _execute
+ return _decorator
diff --git a/qtip/api/controllers/metric.py b/qtip/api/controllers/metric.py
new file mode 100644
index 00000000..96cd985c
--- /dev/null
+++ b/qtip/api/controllers/metric.py
@@ -0,0 +1,25 @@
+##############################################################################
+# 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 httplib
+
+from qtip.api.controllers import common
+from qtip.loader import metric
+
+
+def list_metrics():
+ metrics = list(metric.MetricSpec.list_all())
+ metrics_by_name = [m['name'] for m in metrics]
+ return {'metrics': metrics_by_name}, httplib.OK
+
+
+@common.check_endpoint_for_error(resource='Metric')
+def get_metric(name):
+ metric_spec = metric.MetricSpec(name)
+ return metric_spec.content
diff --git a/qtip/api/controllers/plan.py b/qtip/api/controllers/plan.py
new file mode 100644
index 00000000..00593878
--- /dev/null
+++ b/qtip/api/controllers/plan.py
@@ -0,0 +1,31 @@
+##############################################################################
+# 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 httplib
+
+from qtip.api.controllers import common
+from qtip.base import error
+from qtip.loader import plan
+
+
+def list_plans():
+ plans = list(plan.Plan.list_all())
+ plans_by_name = [p['name'] for p in plans]
+ return {'plans': plans_by_name}, httplib.OK
+
+
+@common.check_endpoint_for_error(resource='Plan')
+def get_plan(name):
+ plan_spec = plan.Plan(name)
+ return plan_spec.content
+
+
+@common.check_endpoint_for_error(resource='Plan', operation='Run')
+def run_plan(name, action="run"):
+ raise error.ToBeDoneError('run_plan', 'plan')
diff --git a/qtip/api/controllers/qpi.py b/qtip/api/controllers/qpi.py
new file mode 100644
index 00000000..af08a824
--- /dev/null
+++ b/qtip/api/controllers/qpi.py
@@ -0,0 +1,25 @@
+##############################################################################
+# 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 httplib
+
+from qtip.api.controllers import common
+from qtip.loader import qpi
+
+
+def list_qpis():
+ qpi_specs = list(qpi.QPISpec.list_all())
+ qpis_by_name = [q['name'] for q in qpi_specs]
+ return {'qpis': qpis_by_name}, httplib.OK
+
+
+@common.check_endpoint_for_error(resource='QPI')
+def get_qpi(name):
+ qpi_spec = qpi.QPISpec(name)
+ return qpi_spec.content
diff --git a/qtip/api/swagger/swagger.yaml b/qtip/api/swagger/swagger.yaml
index 97a9c352..51c3ebb8 100644
--- a/qtip/api/swagger/swagger.yaml
+++ b/qtip/api/swagger/swagger.yaml
@@ -1,9 +1,302 @@
+##############################################################################
+# 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
+##############################################################################
+
swagger: '2.0'
info:
title: QTIP-API
+ version: "1.0"
consumes:
- application/json
produces:
- application/json
paths:
- #TODO (akhil) add paths \ No newline at end of file
+ /plans:
+ get:
+ summary: List all plans
+ operationId: qtip.api.controllers.plan.list_plans
+ tags:
+ - Plan
+ - Standalone
+ responses:
+ 200:
+ description: A list of plans
+ schema:
+ type: array
+ items:
+ $ref: '#/definitions/Plans'
+ 501:
+ description: Resource not implemented
+ schema:
+ $ref: '#/definitions/Error'
+ default:
+ description: Unexpected error
+ schema:
+ $ref: '#/definitions/Error'
+ /plans/{name}:
+ get:
+ summary: Get a plan by plan name
+ operationId: qtip.api.controllers.plan.get_plan
+ tags:
+ - Plan
+ - Standalone
+ parameters:
+ - name: name
+ in: path
+ description: Plan name
+ required: true
+ type: string
+ responses:
+ 200:
+ description: Plan information
+ schema:
+ $ref: '#/definitions/Plan'
+ 404:
+ description: Plan not found
+ schema:
+ $ref: '#/definitions/Error'
+ 501:
+ description: Resource not implemented
+ schema:
+ $ref: '#/definitions/Error'
+ default:
+ description: Unexpected error
+ schema:
+ $ref: '#/definitions/Error'
+ post:
+ summary: Run a plan and return results
+ operationId: qtip.api.controllers.plan.run_plan
+ tags:
+ - Plan
+ - Standalone
+ parameters:
+ - name: name
+ in: path
+ description: Plan name
+ required: true
+ type: string
+ - name: action
+ in: query
+ description: action for a plan
+ required: true
+ type: string
+ responses:
+ 200:
+ description: Result of the run of the plan
+ #TODO (akhil) define schema
+ 404:
+ description: Plan not found
+ schema:
+ $ref: '#/definitions/Error'
+ 400:
+ description: Invalid parameters
+ schema:
+ $ref: '#/definitions/Error'
+ 501:
+ description: Resource not implemented
+ schema:
+ $ref: '#/definitions/Error'
+ default:
+ description: Unexpected error
+ schema:
+ $ref: '#/definitions/Error'
+ /qpis:
+ get:
+ summary: List all QPIs
+ operationId: qtip.api.controllers.qpi.list_qpis
+ tags:
+ - QPI
+ - Standalone
+ - Agent
+ responses:
+ 200:
+ description: A list of QPIs
+ schema:
+ items:
+ $ref: '#/definitions/QPIs'
+ 501:
+ description: Resource not implemented
+ schema:
+ $ref: '#/definitions/Error'
+ default:
+ description: Unexpected error
+ schema:
+ $ref: '#/definitions/Error'
+ /qpis/{name}:
+ get:
+ summary: Get a QPI
+ operationId: qtip.api.controllers.qpi.get_qpi
+ tags:
+ - QPI
+ - Standalone
+ - Agent
+ parameters:
+ - name: name
+ in: path
+ description: QPI name
+ required: true
+ type: string
+ responses:
+ 200:
+ description: QPI information
+ schema:
+ $ref: '#/definitions/QPI'
+ 404:
+ description: QPI not found
+ schema:
+ $ref: '#/definitions/Error'
+ 501:
+ description: Resource not implemented
+ schema:
+ $ref: '#/definitions/Error'
+ default:
+ description: Unexpected error
+ schema:
+ $ref: '#/definitions/Error'
+ /metrics:
+ get:
+ summary: List all metrics
+ operationId: qtip.api.controllers.metric.list_metrics
+ tags:
+ - Metric
+ - Standalone
+ - Agent
+ responses:
+ 200:
+ description: A list of metrics
+ schema:
+ items:
+ $ref: '#/definitions/Metrics'
+ 501:
+ description: Resource not implemented
+ schema:
+ $ref: '#/definitions/Error'
+ default:
+ description: Unexpected error
+ schema:
+ $ref: '#/definitions/Error'
+ /metrics/{name}:
+ get:
+ summary: Get a metric
+ operationId: qtip.api.controllers.metric.get_metric
+ tags:
+ - Metric
+ - Standalone
+ - Agent
+ parameters:
+ - name: name
+ in: path
+ description: Metric name
+ required: true
+ type: string
+ responses:
+ 200:
+ description: Metric information
+ schema:
+ $ref: '#/definitions/Metric'
+ 404:
+ description: Metric not found
+ schema:
+ $ref: '#/definitions/Error'
+ 501:
+ description: Resource not implemented
+ schema:
+ $ref: '#/definitions/Error'
+ default:
+ description: Unexpected error
+ schema:
+ $ref: '#/definitions/Error'
+definitions:
+ Plan:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ description:
+ type: string
+ info:
+ type: object
+ config:
+ type: object
+ QPIs:
+ type: array
+ items:
+ type: object
+ Plans:
+ type: object
+ required:
+ - plans
+ properties:
+ plans:
+ type: array
+ items:
+ type: string
+ Metric:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ description:
+ type: string
+ links:
+ type: array
+ items:
+ type: string
+ workloads:
+ type: array
+ items:
+ type: string
+ Metrics:
+ type: object
+ required:
+ - metrics
+ properties:
+ metrics:
+ type: array
+ items:
+ type: string
+ QPI:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ description:
+ type: string
+ formula:
+ type: string
+ sections:
+ type: array
+ items:
+ type: object
+ QPIs:
+ type: object
+ required:
+ - qpis
+ properties:
+ qpis:
+ type: array
+ items:
+ type: string
+ Error:
+ type: object
+ properties:
+ status:
+ type: integer
+ format: int32
+ title:
+ type: string
+ detail:
+ type: string
+ type:
+ type: string \ No newline at end of file
diff --git a/qtip/cli/commands/cmd_metric.py b/qtip/cli/commands/cmd_metric.py
index b6035e2d..31b7b702 100644
--- a/qtip/cli/commands/cmd_metric.py
+++ b/qtip/cli/commands/cmd_metric.py
@@ -1,5 +1,5 @@
##############################################################################
-# Copyright (c) 2016 ZTE Corp and others.
+# Copyright (c) 2017 taseer94@gmail.com and others.
#
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Apache License, Version 2.0
@@ -9,7 +9,9 @@
import click
+from qtip.cli import utils
from qtip.cli.entry import Context
+from qtip.loader.metric import MetricSpec
pass_context = click.make_pass_decorator(Context, ensure=False)
@@ -24,14 +26,19 @@ def cli(ctx):
@cli.command('list', help='List all the Metric Groups')
@pass_context
def cmd_list(ctx):
- pass
+ metrics = MetricSpec.list_all()
+ table = utils.table('Metrics', metrics)
+ click.echo(table)
@cli.command('show', help='View details of a Metric')
@click.argument('name')
@pass_context
def show(ctx, name):
- pass
+ metric = MetricSpec('{}.yaml'.format(name))
+ cnt = metric.content
+ output = utils.render('metric', cnt)
+ click.echo(output)
@cli.command('run', help='Run tests to run Performance Metrics')
diff --git a/qtip/cli/commands/cmd_plan.py b/qtip/cli/commands/cmd_plan.py
index 64c702d3..90773491 100644
--- a/qtip/cli/commands/cmd_plan.py
+++ b/qtip/cli/commands/cmd_plan.py
@@ -1,5 +1,5 @@
##############################################################################
-# Copyright (c) 2016 ZTE Corp and others.
+# Copyright (c) 2016 taseer94@gmail.com and others.
#
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Apache License, Version 2.0
@@ -10,7 +10,9 @@
import click
+from qtip.cli import utils
from qtip.cli.entry import Context
+from qtip.loader.plan import Plan
pass_context = click.make_pass_decorator(Context, ensure=False)
@@ -32,14 +34,19 @@ def init(ctx):
@cli.command('list', help='List the Plans')
@pass_context
def list(ctx):
- pass
+ plans = Plan.list_all()
+ table = utils.table('Plans', plans)
+ click.echo(table)
@cli.command('show', help='View details of a Plan')
@click.argument('name')
@pass_context
def show(ctx, name):
- pass
+ plan = Plan('{}.yaml'.format(name))
+ cnt = plan.content
+ output = utils.render('plan', cnt)
+ click.echo(output)
@cli.command('run', help='Execute a Plan')
diff --git a/qtip/cli/commands/cmd_qpi.py b/qtip/cli/commands/cmd_qpi.py
index 5fc9bec8..1f23211e 100644
--- a/qtip/cli/commands/cmd_qpi.py
+++ b/qtip/cli/commands/cmd_qpi.py
@@ -1,5 +1,5 @@
##############################################################################
-# Copyright (c) 2016 ZTE Corp and others.
+# Copyright (c) 2017 taseer94@gmail.com and others.
#
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Apache License, Version 2.0
@@ -10,7 +10,9 @@
import click
+from qtip.cli import utils
from qtip.cli.entry import Context
+from qtip.loader.qpi import QPISpec
pass_context = click.make_pass_decorator(Context, ensure=False)
@@ -25,14 +27,19 @@ def cli(ctx):
@cli.command('list', help='List all the QPI specs')
@pass_context
def cmd_list(ctx):
- pass
+ qpis = QPISpec.list_all()
+ table = utils.table('QPIs', qpis)
+ click.echo(table)
@cli.command('show', help='View details of a QPI')
@click.argument('name')
@pass_context
def show(ctx, name):
- pass
+ qpi = QPISpec('{}.yaml'.format(name))
+ cnt = qpi.content
+ output = utils.render('qpi', cnt)
+ click.echo(output)
@cli.command('run', help='Run performance tests for the specified QPI')
diff --git a/qtip/cli/commands/cmd_report.py b/qtip/cli/commands/cmd_report.py
new file mode 100644
index 00000000..cb9c70b6
--- /dev/null
+++ b/qtip/cli/commands/cmd_report.py
@@ -0,0 +1,31 @@
+##############################################################################
+# Copyright (c) 2017 taseer94@gmail.com 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 click
+
+from qtip.cli.entry import Context
+from qtip.reporter.console import ConsoleReporter
+
+pass_context = click.make_pass_decorator(Context, ensure=False)
+
+
+@click.group()
+@pass_context
+def cli(ctx):
+ """ View Qtip results"""
+ pass
+
+
+@cli.command('show')
+@click.argument('metric')
+@pass_context
+def show(ctx, metric):
+ reporter = ConsoleReporter({})
+ report = reporter.render(metric)
+ click.echo(report)
diff --git a/qtip/cli/entry.py b/qtip/cli/entry.py
index 9f51f25e..6cf78b58 100644
--- a/qtip/cli/entry.py
+++ b/qtip/cli/entry.py
@@ -1,5 +1,5 @@
##############################################################################
-# Copyright (c) 2016 ZTE Corp and others.
+# Copyright (c) 2017 taseer94@gmail.com and others.
#
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Apache License, Version 2.0
@@ -7,33 +7,19 @@
# http://www.apache.org/licenses/LICENSE-2.0
##############################################################################
+import click
import os
import sys
-import click
CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'])
+# TODO (taseer) define user friendly error messages
+sys.tracebacklimit = 0
-class Context(object):
-
- ''' TODO(taseer) implementation'''
-
- def __init__(self):
- self.verbose = False
- self.debug = False
-
- def log(self, msg, *args):
- ''' Log message to stderr '''
- pass
- def verbose(self, msg, *args):
- ''' Log message to stderr when verbose '''
- pass
-
- def debug(self, msg, *args):
- ''' Log message to debug '''
- pass
+class Context(object):
+ """ Load configuration and pass to subcommands """
pass_context = click.make_pass_decorator(Context, ensure=True)
@@ -70,4 +56,5 @@ class QtipCli(click.MultiCommand):
@click.version_option('dev')
@pass_context
def cli(ctx, verbose, debug):
- pass
+ if debug:
+ sys.tracebacklimit = 8
diff --git a/qtip/cli/templates/metric.j2 b/qtip/cli/templates/metric.j2
new file mode 100644
index 00000000..126587f9
--- /dev/null
+++ b/qtip/cli/templates/metric.j2
@@ -0,0 +1,6 @@
+Name: {{ name }}
+Description: {{ description }}
+Workloads:
+{% for wl in workloads %}
+ {{ wl }}
+{% endfor %}
diff --git a/qtip/cli/templates/plan.j2 b/qtip/cli/templates/plan.j2
new file mode 100644
index 00000000..c9adccc8
--- /dev/null
+++ b/qtip/cli/templates/plan.j2
@@ -0,0 +1,2 @@
+Name: {{ name }}
+Description: {{ description }}
diff --git a/qtip/cli/templates/qpi.j2 b/qtip/cli/templates/qpi.j2
new file mode 100644
index 00000000..cc85f10d
--- /dev/null
+++ b/qtip/cli/templates/qpi.j2
@@ -0,0 +1,12 @@
+Name: {{ title }}
+Description: {{ description }}
+{% for section in sections %}
+ Name: {{ section.name }}
+ Weight: {{ section.weight }}
+ Formula: {{ section.formula }}
+ Metrics:
+ {% for metric in section.metrics %}
+ {{ metric }}
+ {% endfor %}
+{% endfor %}
+
diff --git a/qtip/cli/utils.py b/qtip/cli/utils.py
new file mode 100644
index 00000000..a7473236
--- /dev/null
+++ b/qtip/cli/utils.py
@@ -0,0 +1,31 @@
+##############################################################################
+# Copyright (c) 2017 taseer94@gmail.com 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 jinja2 import Environment
+from jinja2 import FileSystemLoader
+from os import path
+from prettytable import PrettyTable
+
+
+def table(name, components):
+ """ Return a PrettyTable for component listing """
+ table = PrettyTable([name])
+ table.align[name] = 'l'
+ [table.add_row([component['name'][0:-5]]) for component in components]
+ return table
+
+
+def render(name, var_dict):
+ """ Get the templates to render for specific component """
+ tmpl_path = path.join(path.dirname(__file__), 'templates')
+ tmpl_loader = FileSystemLoader(tmpl_path)
+ env = Environment(loader=tmpl_loader)
+ template = env.get_template('{}.j2'.format(name))
+ result = template.render(var_dict)
+ return result
diff --git a/qtip/collector/calculator.py b/qtip/collector/calculator.py
new file mode 100644
index 00000000..c3d961b3
--- /dev/null
+++ b/qtip/collector/calculator.py
@@ -0,0 +1,38 @@
+##############################################################################
+# Copyright (c) 2017 ZTE Corp 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 operator import add
+
+from qtip.util.logger import QtipLogger
+
+logger = QtipLogger('calculator').get
+
+
+def dpi_calculator(samples):
+ try:
+ float_pps = map(lambda x: float(x), samples['pps'])
+ float_bps = map(lambda x: float(x), samples['bps'])
+ sum_dpi_pps = reduce(add,
+ map(lambda x: x / 1000 if x > 100 else x, float_pps))
+ sum_dpi_bps = reduce(add,
+ map(lambda x: x / 1000 if x > 100 else x, float_bps))
+
+ return {'pps': round(sum_dpi_pps / 10, 3), 'bps': round(sum_dpi_bps / 10, 3)}
+ except Exception as error:
+ logger.error(error)
+ return {'pps': None, 'bps': None}
+
+
+def calculate_cpu_usage(cpu_idle):
+ try:
+ cpu_usage = round((100.0 - float(cpu_idle)), 3)
+ return '{0}%'.format(str(cpu_usage))
+ except Exception, error:
+ logger.error(error)
+ return None
diff --git a/qtip/collector/logfile.py b/qtip/collector/logfile.py
index 2c2e532f..5f0951cb 100644
--- a/qtip/collector/logfile.py
+++ b/qtip/collector/logfile.py
@@ -18,8 +18,8 @@ from qtip.loader.file import FileLoader
class LogItem(BaseActor):
- def find(self, filename, paths=None):
- return self._parent.find(filename, paths)
+ def find(self, filename):
+ return self._parent.find(filename)
class LogfileCollector(BaseActor):
@@ -33,8 +33,7 @@ class LogfileCollector(BaseActor):
self._parent = parent # plan
# TODO(yujunz) handle exception of invalid parent
dirname = os.path.dirname(self._parent.abspath)
- paths = [os.path.join(dirname, p) for p in config.get(self.PATHS, [])]
- self._loader = FileLoader('.', paths)
+ self.paths = [os.path.join(dirname, p) for p in config.get(self.PATHS, [])]
def run(self):
collected = []
@@ -45,8 +44,8 @@ class LogfileCollector(BaseActor):
collected = chain(collected, reduce(chain, matches))
return reduce(merge_matchobj_to_dict, collected, {'groups': (), 'groupdict': {}})
- def find(self, filename, paths=None):
- return self._loader.find(filename, paths)
+ def find(self, filename):
+ return FileLoader.find(filename, self.paths)
def merge_matchobj_to_dict(d, m):
diff --git a/qtip/collector/parser/grep.py b/qtip/collector/parser/grep.py
index f74ce403..d3a8210a 100644
--- a/qtip/collector/parser/grep.py
+++ b/qtip/collector/parser/grep.py
@@ -7,12 +7,20 @@
# http://www.apache.org/licenses/LICENSE-2.0
##############################################################################
-
+from collections import defaultdict
+from os import path
import re
+import yaml
-from qtip.base.constant import BaseProp
from qtip.base import BaseActor
+from qtip.base.constant import BaseProp
+from qtip.collector import calculator
+from qtip.util.logger import QtipLogger
+
+logger = QtipLogger('grep').get
+
+REGEX_FILE = path.join(path.dirname(__file__), 'regex.yaml')
class GrepProp(BaseProp):
@@ -32,3 +40,63 @@ def grep_in_file(filename, regex):
with open(filename, 'r') as f:
return filter(lambda x: x is not None,
re.finditer(regex, f.read(), re.MULTILINE))
+
+
+def _parse_logfile(config, paths):
+ captured = {}
+ for regex_rules_by_file in config:
+ filename = \
+ '{0}/{1}'.format(paths, regex_rules_by_file[GrepProp.FILENAME])
+ for regex in regex_rules_by_file['grep']:
+ matches = grep_in_file(filename, regex)
+ if len(matches) > 1:
+ temp_dict = defaultdict(list)
+ for item in [match.groupdict() for match in matches]:
+ for key in item:
+ temp_dict[key].append(item[key])
+ captured.update(temp_dict)
+ elif len(matches) == 1:
+ captured.update(matches[0].groupdict())
+ else:
+ logger.error("Nothing is matched from {0}".format(filename))
+ return captured
+
+
+# TODO: Hardcord in Danube, it will be removed in the future.
+def parse_sysinfo(config, result_dir):
+ sysinfo = _parse_logfile(config, result_dir)
+ if "cpu_idle" in sysinfo:
+ sysinfo['cpu_usage'] = \
+ calculator.calculate_cpu_usage(sysinfo['cpu_idle'])
+ sysinfo.pop('cpu_idle')
+ return sysinfo
+
+
+# TODO: Hardcord in Danube, it will be removed in the future.
+def parse_test_result(benchmark, config, result_dir):
+ test_result = _parse_logfile(config, result_dir)
+ if benchmark == 'dpi':
+ return calculator.dpi_calculator(test_result)
+ if benchmark == 'dhrystone' or benchmark == 'whetstone':
+ return {'total_cpus': test_result['total_cpus'],
+ 'single_cpu': {'num': test_result['single_cpu'],
+ 'score': test_result['score'][0]},
+ 'multi_cpus': {'num': test_result['multi_cpus'],
+ 'score': test_result['score'][1]}}
+ return test_result
+
+
+# TODO: Hardcord in Danube, it will be removed in the future.
+def parse_benchmark_result(result_dir):
+ regex_config = yaml.safe_load(file(REGEX_FILE))
+ benchmark = result_dir.split('/')[-1]
+ result = {'name': benchmark}
+
+ test_result = \
+ parse_test_result(benchmark, regex_config[benchmark], result_dir)
+ result['results'] = test_result.copy()
+
+ sysinfo = parse_sysinfo(regex_config['sysinfo'], result_dir)
+ result['sysinfo'] = sysinfo.copy()
+
+ return result
diff --git a/qtip/collector/parser/regex.yaml b/qtip/collector/parser/regex.yaml
new file mode 100644
index 00000000..397f8973
--- /dev/null
+++ b/qtip/collector/parser/regex.yaml
@@ -0,0 +1,85 @@
+##############################################################################
+# 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
+##############################################################################
+
+dhrystone:
+ - filename: dhrystone
+ grep:
+ - '^(?P<total_cpus>\d+)\sCPUs in system; running 1 parallel copy of tests$'
+ - '.+\srunning (?P<single_cpu>\d+) parallel copy of tests$'
+ - '.+\srunning (?P<multi_cpus>\d+) parallel copies of tests$'
+ - '^System Benchmarks Index Score \(Partial Only\)\s+(?P<score>\d+\.\d)$'
+whetstone:
+ - filename: whetstone
+ grep:
+ - '^(?P<total_cpus>\d+)\sCPUs in system; running 1 parallel copy of tests$'
+ - '.+\srunning (?P<single_cpu>\d+) parallel copy of tests$'
+ - '.+\srunning (?P<multi_cpus>\d+) parallel copies of tests$'
+ - '^System Benchmarks Index Score \(Partial Only\)\s+(?P<score>\d+\.\d)$'
+dpi:
+ - filename: dpi_dump.txt
+ grep:
+ - |-
+ ^\s+nDPI throughput:.+?(?P<pps>\d+.\d+)\sM\spps.+
+ ?(?P<bps>\d+.\d+)\sGb\/sec
+ramspeed:
+ - filename: Intmem
+ grep:
+ - '^INTEGER\s+BatchRun\s+Copy:\s+?(?P<integer_copy>\d+\.\d+)\sMB/s$'
+ - '^INTEGER\s+BatchRun\s+Scale:\s+?(?P<integer_scale>\d+\.\d+)\sMB/s$'
+ - '^INTEGER\s+BatchRun\s+Add:\s+?(?P<integer_add>\d+\.\d+)\sMB/s$'
+ - '^INTEGER\s+BatchRun\s+Triad:\s+?(?P<integer_triad>\d+\.\d+)\sMB/s$'
+ - '^INTEGER\s+BatchRun\s+AVERAGE:\s+?(?P<integer_average>\d+\.\d+)\sMB/s$'
+ - filename: Floatmem
+ grep:
+ - '^FL-POINT\s+BatchRun\s+Copy:\s+?(?P<float_copy>\d+\.\d+)\sMB/s$'
+ - '^FL-POINT\s+BatchRun\s+Scale:\s+?(?P<float_scale>\d+\.\d+)\sMB/s$'
+ - '^FL-POINT\s+BatchRun\s+Add:\s+?(?P<float_add>\d+\.\d+)\sMB/s$'
+ - '^FL-POINT\s+BatchRun\s+Triad:\s+?(?P<float_triad>\d+\.\d+)\sMB/s$'
+ - '^FL-POINT\s+BatchRun\s+AVERAGE:\s+?(?P<float_average>\d+\.\d+)\sMB/s$'
+ssl:
+ - filename: RSA_dump
+ grep:
+ - |-
+ ^rsa\s+512\sbits\s.+
+ ?(?P<rsa_sign_512>\d+\.\d)\s+
+ ?(?P<rsa_verify_512>\d+\.\d)$
+ - |-
+ ^rsa\s+1024\sbits\s.+
+ ?(?P<rsa_sign_1024>\d+\.\d)\s+
+ ?(?P<rsa_verify_1024>\d+\.\d)$
+ - |-
+ ^rsa\s+2048\sbits\s.+
+ ?(?P<rsa_sign_2048>\d+\.\d)\s+
+ ?(?P<rsa_verify_2048>\d+\.\d)$
+ - |-
+ ^rsa\s+4096\sbits\s.+
+ ?(?P<rsa_sign_4096>\d+\.\d)\s+
+ ?(?P<rsa_verify_4096>\d+\.\d)$
+ - filename: AES-128-CBC_dump
+ grep:
+ - |-
+ ^aes-128-cbc\s+
+ ?(?P<aes_128_cbc_16_bytes>\d+\.\w+)\s+
+ ?(?P<aes_128_cbc_64_bytes>\d+\.\w+)\s+
+ ?(?P<aes_128_cbc_256_bytes>\d+\.\w+)\s+
+ ?(?P<aes_128_cbc_1024_bytes>\d+\.\w+)\s+
+ ?(?P<aes_128_cbc_8192_bytes>\d+\.\w+)$
+sysinfo:
+ - filename: top.log
+ grep:
+ - 'Cpu\(s\):.+?(?P<cpu_idle>\d+\.\d)\sid'
+ - filename: inxi.log
+ grep:
+ - '.+\s+Host:\s+(?P<hostname>.+)\sKernel'
+ - '.+\sMemory:\s+(?P<memory>.+MB)\s'
+ - '^CPU\(s\):\s+(?P<cpu>.+)'
+ - '.+\sDistro:\s+(?P<os>.+)'
+ - '.+\sKernel:\s+(?P<kernel>.+)\sConsole'
+ - '.+\s+HDD Total Size:\s+(?P<disk>.+)\s'
+ - '.+\sproduct:\s+(?P<product>.+)\sv' \ No newline at end of file
diff --git a/qtip/driver/ansible_api.py b/qtip/driver/ansible_api.py
new file mode 100644
index 00000000..5c5baffc
--- /dev/null
+++ b/qtip/driver/ansible_api.py
@@ -0,0 +1,58 @@
+##############################################################################
+# Copyright (c) 2017 ZTE Corp 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 collections import namedtuple
+
+from ansible.executor.playbook_executor import PlaybookExecutor
+from ansible.inventory import Inventory
+from ansible.parsing.dataloader import DataLoader
+from ansible.vars import VariableManager
+
+
+class AnsibleApi(object):
+
+ def __init__(self):
+ self.variable_manager = VariableManager()
+ self.loader = DataLoader()
+ self.passwords = {}
+ self.playbook_executor = None
+
+ def execute_playbook(self, playbook_path, hosts_file=None,
+ key_file=None, extra_vars=None):
+ inventory = Inventory(loader=self.loader,
+ variable_manager=self.variable_manager,
+ host_list=hosts_file)
+ Options = namedtuple('Options',
+ ['listtags', 'listtasks', 'listhosts', 'syntax',
+ 'connection', 'module_path', 'forks', 'remote_user',
+ 'private_key_file', 'ssh_common_args', 'ssh_extra_args',
+ 'sftp_extra_args', 'scp_extra_args', 'become',
+ 'become_method', 'become_user', 'verbosity', 'check'])
+ options = Options(listtags=False, listtasks=False, listhosts=False,
+ syntax=False, connection='ssh', module_path=None,
+ forks=100, remote_user='root', private_key_file=key_file,
+ ssh_common_args=None, ssh_extra_args=None, sftp_extra_args=None,
+ scp_extra_args=None, become=None, become_method=None,
+ become_user='root', verbosity=None, check=False)
+ self.variable_manager.extra_vars = extra_vars
+
+ self.playbook_executor = PlaybookExecutor(playbooks=[playbook_path],
+ inventory=inventory,
+ variable_manager=self.variable_manager,
+ loader=self.loader,
+ options=options,
+ passwords=self.passwords)
+ return self.playbook_executor.run()
+
+ def get_detail_playbook_stats(self):
+ if self.playbook_executor:
+ stats = self.playbook_executor._tqm._stats
+ return map(lambda x: (x, stats.summarize(x)), stats.processed.keys())
+ else:
+ return None
diff --git a/qtip/driver/ansible_driver.py b/qtip/driver/ansible_driver.py
new file mode 100644
index 00000000..34ef46ed
--- /dev/null
+++ b/qtip/driver/ansible_driver.py
@@ -0,0 +1,102 @@
+##############################################################################
+# Copyright (c) 2017 ZTE Corp 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 collections import defaultdict
+from os import path
+from operator import add
+
+from qtip.driver.ansible_api import AnsibleApi
+from qtip.util.env import AnsibleEnvSetup
+from qtip.util.logger import QtipLogger
+
+logger = QtipLogger('ansible_driver').get
+PLAYBOOK_DIR = path.join(path.dirname(__file__), 'playbook')
+
+
+class AnsibleDriver(object):
+ """driver for running performance tests with Ansible"""
+
+ def __init__(self, config={}):
+ self.config = config
+ self.env = AnsibleEnvSetup()
+ self.env_setup_flag = False
+
+ @staticmethod
+ def merge_two_dicts(x, y):
+ '''
+ It is from http://stackoverflow.com/questions/38987/
+ how-can-i-merge-two-python-dictionaries-in-a-single-expression
+ '''
+ z = x.copy()
+ z.update(y)
+ return z
+
+ def pre_run(self):
+ if self.env_setup_flag:
+ logger.info("Already setup environment......")
+ else:
+ logger.info("Starting to setup test environment...")
+ self.env.setup(self.config)
+ self.env_setup_flag = True
+ logger.info("Setup test enviroment, Done!")
+
+ def cleanup(self):
+ self.env.cleanup()
+
+ def run(self, metric_list, **kwargs):
+ if 'args' in self.config:
+ extra_vars = self.merge_two_dicts(kwargs, self.config['args'])
+ else:
+ extra_vars = kwargs
+ logger.info("extra_var: {0}".format(extra_vars))
+
+ tool_to_metrics = defaultdict(list)
+ for metric in metric_list:
+ if metric == 'dhrystone' or metric == 'whetstone':
+ tool_to_metrics['unixbench'].append(metric)
+ extra_vars[metric] = True
+ elif metric == 'ssl':
+ tool_to_metrics['openssl'].append(metric)
+ else:
+ tool_to_metrics[metric].append(metric)
+
+ result_list = map(lambda tool: self._run_metric(tool,
+ tool_to_metrics[tool],
+ extra_vars),
+ tool_to_metrics)
+ return False not in result_list
+
+ def _run_metric(self, tool, metrics, extra_vars):
+ logger.info('Using {0} to measure metrics {1}'.format(tool, metrics))
+
+ setup_pbook = "{0}/{1}/setup.yaml".format(PLAYBOOK_DIR, tool)
+ run_pbook = "{0}/{1}/run.yaml".format(PLAYBOOK_DIR, tool)
+ clean_pbook = "{0}/{1}/clean.yaml".format(PLAYBOOK_DIR, tool)
+
+ if self._run_ansible_playbook(setup_pbook, extra_vars):
+ self._run_ansible_playbook(run_pbook, extra_vars)
+ else:
+ logger.error("{0} is failed.".format(setup_pbook))
+
+ return self._run_ansible_playbook(clean_pbook, extra_vars)
+
+ def _run_ansible_playbook(self, pbook, extra_vars):
+ ansible_api = AnsibleApi()
+ logger.debug("Run {0} with extra_vars: {1}".format(pbook, extra_vars))
+ ansible_api.execute_playbook(pbook, self.env.hostfile,
+ self.env.keypair['private'], extra_vars)
+ playbook_stats = ansible_api.get_detail_playbook_stats()
+ logger.debug("playbook_stat: {0}".format(playbook_stats))
+ return self.is_pass(playbook_stats)
+
+ @staticmethod
+ def is_pass(stats):
+ return 0 == reduce(add,
+ map(lambda x: x[1]['failures'] + x[1]['unreachable'],
+ stats))
diff --git a/qtip/driver/ansible/playbook/bwn_ng.yaml b/qtip/driver/playbook/bwn_ng.yaml
index 99477856..c52cb14e 100644
--- a/qtip/driver/ansible/playbook/bwn_ng.yaml
+++ b/qtip/driver/playbook/bwn_ng.yaml
@@ -20,4 +20,6 @@
when: ansible_os_family == "Debian"
- name: Run bwm-ng
- shell: bwm-ng -o plain -c 1 > $HOME/qtip_result/bwm-dump.log \ No newline at end of file
+ shell: bwm-ng -o plain -c 1 > bwm-dump.log
+ args:
+ chdir: '{{ dest_path }}' \ No newline at end of file
diff --git a/qtip/driver/playbook/dpi/clean.yaml b/qtip/driver/playbook/dpi/clean.yaml
new file mode 100644
index 00000000..0b9f9291
--- /dev/null
+++ b/qtip/driver/playbook/dpi/clean.yaml
@@ -0,0 +1,23 @@
+##############################################################################
+# 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
+##############################################################################
+
+- hosts: hosts
+ become: yes
+ remote_user: root
+
+ tasks:
+ - name: Cleaning tempD
+ file:
+ path: '{{ ansible_env.HOME }}/tempD'
+ state: absent
+
+ - name: Cleaning qtip_result
+ file:
+ path: '{{ ansible_env.HOME }}/qtip_result'
+ state: absent
diff --git a/qtip/driver/playbook/dpi/dpi_average.sh b/qtip/driver/playbook/dpi/dpi_average.sh
new file mode 100644
index 00000000..6f038053
--- /dev/null
+++ b/qtip/driver/playbook/dpi/dpi_average.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+COUNTER=0
+WDIR=$PWD
+while [ $COUNTER -lt 10 ]; do
+ echo $WDIR
+ $( ./ndpiReader -i test.pcap >> $WDIR/dpi_dump.txt )
+ let COUNTER=COUNTER+1
+ echo "Run number: $COUNTER"
+done \ No newline at end of file
diff --git a/qtip/driver/playbook/dpi/run.yaml b/qtip/driver/playbook/dpi/run.yaml
new file mode 100644
index 00000000..f4c8c457
--- /dev/null
+++ b/qtip/driver/playbook/dpi/run.yaml
@@ -0,0 +1,42 @@
+##############################################################################
+# 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
+##############################################################################
+
+- hosts: hosts
+ become: yes
+ remote_user: root
+
+ tasks:
+ - name: Make some directories needed
+ file:
+ path: '{{ ansible_env.HOME }}/qtip_result/{{ ansible_hostname }}/dpi/'
+ state: directory
+
+ - include: ../inxi.yaml
+ vars:
+ dest_path: '{{ ansible_env.HOME }}/qtip_result/{{ ansible_hostname }}/dpi/'
+
+ - include: ../top.yaml
+ vars:
+ dest_path: '{{ ansible_env.HOME }}/qtip_result/{{ ansible_hostname }}/dpi/'
+
+ - name: Run nDPI benchmark
+ shell: ./dpi_average.sh
+ args:
+ chdir: '{{ ansible_env.HOME }}/tempD/nDPI/example/'
+
+ - name: Copying result and system info to qtip result directory
+ command: cp $HOME/tempD/nDPI/example/dpi_dump.txt ./
+ args:
+ chdir: '{{ ansible_env.HOME }}/qtip_result/{{ ansible_hostname }}/dpi/'
+
+ - name: Fetch result files to local manchine
+ synchronize:
+ mode: pull
+ src: '{{ ansible_env.HOME }}/qtip_result/'
+ dest: '{{ result_dir }}/'
diff --git a/qtip/driver/playbook/dpi/setup.yaml b/qtip/driver/playbook/dpi/setup.yaml
new file mode 100644
index 00000000..76e62e6d
--- /dev/null
+++ b/qtip/driver/playbook/dpi/setup.yaml
@@ -0,0 +1,93 @@
+##############################################################################
+# 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
+##############################################################################
+
+- hosts: localhost
+ connection: local
+ gather_facts: no
+
+ tasks:
+ - name: Making Dpi directory
+ file:
+ path: '{{ result_dir }}/'
+ state: directory
+
+- hosts: hosts
+ become: yes
+ remote_user: root
+
+ tasks:
+ - name: Cleaning tempD directory
+ file:
+ path: '{{ ansible_env.HOME }}/tempD'
+ state: absent
+
+ - name: Cleaning qtip_result directory
+ file:
+ path: '{{ ansible_env.HOME }}/qtip_result'
+ state: absent
+
+ - include: ../prepare_env.yaml
+
+ - 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: '{{ item }}'
+ state: present
+ when: ansible_os_family == "Debian"
+ with_items:
+ - git
+ - gcc
+ - patch
+ - autoconf
+ - automake
+ - libpcap-dev
+ - libtool
+
+ - name: Making nDPI temporary directory
+ file:
+ path: '{{ ansible_env.HOME }}/tempD'
+ state: directory
+
+ - name: Clone nDPI
+ git:
+ repo: https://github.com/ntop/nDPI.git
+ dest: '{{ ansible_env.HOME }}/tempD/nDPI'
+
+ - name: Run autogen && configure Dpi && make Dpi
+ command: '{{ item }}'
+ with_items:
+ - ./autogen.sh
+ - ./configure
+ - make
+ args:
+ chdir: '{{ ansible_env.HOME }}/tempD/nDPI/'
+
+ - name: Fetching Test_pcap file
+ get_url:
+ url: http://build.opnfv.org/artifacts.opnfv.org/qtip/utilities/test.pcap
+ dest: '{{ ansible_env.HOME }}/tempD/nDPI/example/test.pcap'
+
+ - name: Fetch Averaging script
+ copy:
+ src: ./dpi_average.sh
+ dest: '{{ ansible_env.HOME }}/tempD/nDPI/example'
+ mode: 777 \ No newline at end of file
diff --git a/qtip/driver/ansible/playbook/inxi.yaml b/qtip/driver/playbook/inxi.yaml
index f6a0311d..2a4d9b3f 100644
--- a/qtip/driver/ansible/playbook/inxi.yaml
+++ b/qtip/driver/playbook/inxi.yaml
@@ -20,4 +20,6 @@
when: ansible_os_family == "Debian"
- name: Run inxi
- shell: inxi -b -c0 -n > $HOME/qtip_result/inxi.log
+ shell: inxi -b -c0 -n > inxi.log
+ args:
+ chdir: '{{ dest_path }}'
diff --git a/qtip/driver/playbook/openssl/clean.yaml b/qtip/driver/playbook/openssl/clean.yaml
new file mode 100644
index 00000000..0139ba54
--- /dev/null
+++ b/qtip/driver/playbook/openssl/clean.yaml
@@ -0,0 +1,23 @@
+##############################################################################
+# 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
+##############################################################################
+
+- hosts: hosts
+ become: yes
+ remote_user: root
+
+ tasks:
+ - name: Cleaning Open_SSL
+ file:
+ path: '{{ ansible_env.HOME }}/Open_SSL'
+ state: absent
+
+ - name: Cleaning qtip_result
+ file:
+ path: '{{ ansible_env.HOME }}/qtip_result'
+ state: absent
diff --git a/qtip/driver/playbook/openssl/run.yaml b/qtip/driver/playbook/openssl/run.yaml
new file mode 100644
index 00000000..db923fed
--- /dev/null
+++ b/qtip/driver/playbook/openssl/run.yaml
@@ -0,0 +1,45 @@
+##############################################################################
+# 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
+##############################################################################
+
+- hosts: hosts
+ become: yes
+ remote_user: root
+
+ tasks:
+ - name: Make some directories needed
+ file:
+ path: '{{ ansible_env.HOME }}/qtip_result/{{ ansible_hostname }}/ssl/'
+ state: directory
+
+ - include: ../inxi.yaml
+ vars:
+ dest_path: '{{ ansible_env.HOME }}/qtip_result/{{ ansible_hostname }}/ssl/'
+
+ - include: ../top.yaml
+ vars:
+ dest_path: '{{ ansible_env.HOME }}/qtip_result/{{ ansible_hostname }}/ssl/'
+
+ - name: Benchmarking RSA signatures and AES-128-cbc cipher encryption throughput
+ shell: '{{ item }}'
+ with_items:
+ - ./openssl speed rsa >> RSA_dump
+ - ./openssl speed -evp aes-128-cbc >> AES-128-CBC_dump
+ args:
+ chdir: '{{ ansible_env.HOME }}/Open_SSL/openssl-1.0.2f/apps'
+
+ - name: Copying result to qtip result directory
+ shell: cp ~/Open_SSL/openssl-1.0.2f/apps/*_dump ./
+ args:
+ chdir: '{{ ansible_env.HOME }}/qtip_result/{{ ansible_hostname }}/ssl/'
+
+ - name: Fetch result files to local manchine
+ synchronize:
+ mode: pull
+ src: '{{ ansible_env.HOME }}/qtip_result/'
+ dest: '{{ result_dir }}/'
diff --git a/qtip/driver/playbook/openssl/setup.yaml b/qtip/driver/playbook/openssl/setup.yaml
new file mode 100644
index 00000000..3a6f385a
--- /dev/null
+++ b/qtip/driver/playbook/openssl/setup.yaml
@@ -0,0 +1,87 @@
+##############################################################################
+# 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
+##############################################################################
+
+- hosts: localhost
+ connection: local
+ gather_facts: no
+
+ tasks:
+ - name: Making ssl directory
+ file:
+ path: '{{ result_dir }}/'
+ state: directory
+
+- hosts: hosts
+ become: yes
+ remote_user: root
+
+ tasks:
+ - name: Cleaning Open_SSL directory
+ file:
+ path: '{{ ansible_env.HOME }}/Open_SSL'
+ state: absent
+
+ - name: Cleaning qtip_result directory
+ file:
+ path: '{{ ansible_env.HOME }}/qtip_result'
+ state: absent
+
+ - include: ../prepare_env.yaml
+
+ - name: Installing UnixBench dependencies if CentOS
+ yum:
+ name: '{{ item }}'
+ state: present
+ when: ansible_os_family == "RedHat"
+ with_items:
+ - git
+ - gcc
+ - patch
+ - perl-Time-HiRes
+ - wget
+ - autofconf
+ - automake
+ - libpcap-devel
+ - libtool
+
+ - name: Installing UnixBench dependencies if Ubuntu
+ apt:
+ name: '{{ item }}'
+ state: present
+ when: ansible_os_family == "Debian"
+ with_items:
+ - git
+ - gcc
+ - patch
+ - perl
+ - wget
+ - autoconf
+ - automake
+ - libpcap-dev
+ - libtool
+
+ - name: Make Open_SSL directory
+ file:
+ path: '{{ ansible_env.HOME }}/Open_SSL'
+ state: directory
+
+ - name: Untar OpenSSL
+ unarchive:
+ src: http://artifacts.opnfv.org/qtip/utilities/openssl-1.0.2f.tar.gz
+ dest: '{{ ansible_env.HOME }}/Open_SSL/'
+ remote_src: True
+
+ - name: Configure && Make && Install OpenSSL
+ shell: "{{ item }}"
+ with_items:
+ - ./config
+ - make
+ - make install
+ args:
+ chdir: '{{ ansible_env.HOME }}/Open_SSL/openssl-1.0.2f' \ No newline at end of file
diff --git a/qtip/driver/ansible/playbook/prepare_env.yaml b/qtip/driver/playbook/prepare_env.yaml
index 0595d988..1ec71520 100644
--- a/qtip/driver/ansible/playbook/prepare_env.yaml
+++ b/qtip/driver/playbook/prepare_env.yaml
@@ -10,7 +10,7 @@
yum:
name: epel-release
state: present
- when: ansible_os_family == "RedHat"
+ when: ansible_os_family == "RedHat"
- name: Software Properties Common
apt:
@@ -40,3 +40,15 @@
name: python-selinux
state: present
when: ansible_os_family == "Debian"
+
+- name: Install rsync when CentOS
+ yum:
+ name: rsync
+ state: present
+ when: ansible_os_family == "RedHat"
+
+- name: Install rsync when Ubuntu
+ apt:
+ name: rsync
+ state: present
+ when: ansible_os_family == "Debian"
diff --git a/qtip/driver/playbook/ramspeed/clean.yaml b/qtip/driver/playbook/ramspeed/clean.yaml
new file mode 100644
index 00000000..f0188159
--- /dev/null
+++ b/qtip/driver/playbook/ramspeed/clean.yaml
@@ -0,0 +1,23 @@
+##############################################################################
+# 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
+##############################################################################
+
+- hosts: hosts
+ become: yes
+ remote_user: root
+
+ tasks:
+ - name: Cleaning ramspeed
+ file:
+ path: '{{ ansible_env.HOME }}/ramspeed'
+ state: absent
+
+ - name: Cleaning qtip_result
+ file:
+ path: '{{ ansible_env.HOME }}/qtip_result'
+ state: absent
diff --git a/qtip/driver/playbook/ramspeed/run.yaml b/qtip/driver/playbook/ramspeed/run.yaml
new file mode 100644
index 00000000..496cd5db
--- /dev/null
+++ b/qtip/driver/playbook/ramspeed/run.yaml
@@ -0,0 +1,40 @@
+##############################################################################
+# 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
+##############################################################################
+
+- hosts: hosts
+ become: yes
+ remote_user: root
+
+ tasks:
+ - name: Make some directories needed
+ file:
+ path: '{{ ansible_env.HOME }}/qtip_result/{{ ansible_hostname }}/ramspeed/'
+ state: directory
+
+ - include: ../inxi.yaml
+ vars:
+ dest_path: '{{ ansible_env.HOME }}/qtip_result/{{ ansible_hostname }}/ramspeed/'
+
+ - include: ../top.yaml
+ vars:
+ dest_path: '{{ ansible_env.HOME }}/qtip_result/{{ ansible_hostname }}/ramspeed/'
+
+ - name: Benchmarking IntMem Bandwidth and FloatMem Bandwidth
+ shell: '{{ item }}'
+ with_items:
+ - ~/ramspeed/ramsmp-3.5.0/ramsmp -b 3 -l 5 -p 1 >> Intmem
+ - ~/ramspeed/ramsmp-3.5.0/ramsmp -b 6 -l 5 -p 1 >> Floatmem
+ args:
+ chdir: '{{ ansible_env.HOME }}/qtip_result/{{ ansible_hostname }}/ramspeed/'
+
+ - name: Fetch result files to local manchine
+ synchronize:
+ mode: pull
+ src: '{{ ansible_env.HOME }}/qtip_result/'
+ dest: '{{ result_dir }}/'
diff --git a/qtip/driver/playbook/ramspeed/setup.yaml b/qtip/driver/playbook/ramspeed/setup.yaml
new file mode 100644
index 00000000..842bbda2
--- /dev/null
+++ b/qtip/driver/playbook/ramspeed/setup.yaml
@@ -0,0 +1,70 @@
+##############################################################################
+# 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
+##############################################################################
+
+- hosts: localhost
+ connection: local
+ gather_facts: no
+
+ tasks:
+ - name: Making ramspeed directory
+ file:
+ path: '{{ result_dir }}/'
+ state: directory
+
+- hosts: hosts
+ become: yes
+ remote_user: root
+
+ tasks:
+ - name: Cleaning ramspeed directory
+ file:
+ path: '{{ ansible_env.HOME }}/ramspeed'
+ state: absent
+
+ - name: Cleaning qtip_result directory
+ file:
+ path: '{{ ansible_env.HOME }}/qtip_result'
+ state: absent
+
+ - include: ../prepare_env.yaml
+
+ - name: Installing RAM_Speed dependencies if CentOS
+ yum:
+ name: '{{ item }}'
+ state: present
+ when: ansible_os_family == "RedHat"
+ with_items:
+ - gcc
+ - wget
+
+ - name: Installing RAM_Speed dependencies if Ubuntu
+ apt:
+ name: '{{ item }}'
+ state: present
+ when: ansible_os_family == "Debian"
+ with_items:
+ - gcc
+ - wget
+
+ - name: Making ramspeed temporary directory
+ file:
+ path: '{{ ansible_env.HOME }}/ramspeed'
+ state: directory
+
+ - name: Fetch and untar ramspeed.tar.gz
+ unarchive:
+ # TODO: Need to upload this file to http://artifacts.opnfv.org/qtip/utilities
+ src: https://docs.google.com/uc?id=0B92Bp5LZTM7gRFctalZLMktTNDQ
+ dest: '{{ ansible_env.HOME }}/ramspeed/'
+ remote_src: True
+
+ - name: Build ramsmp
+ shell: ./build.sh
+ args:
+ chdir: '{{ ansible_env.HOME }}/ramspeed/ramsmp-3.5.0'
diff --git a/qtip/driver/ansible/playbook/top.yaml b/qtip/driver/playbook/top.yaml
index 8de7e3d6..dfa0aff2 100644
--- a/qtip/driver/ansible/playbook/top.yaml
+++ b/qtip/driver/playbook/top.yaml
@@ -7,4 +7,6 @@
# http://www.apache.org/licenses/LICENSE-2.0
##############################################################################
- name: Collect cpu usage
- shell: top -bn1 > $HOME/qtip_result/top.log
+ shell: top -bn1 > top.log
+ args:
+ chdir: '{{ dest_path }}'
diff --git a/qtip/driver/playbook/unixbench/clean.yaml b/qtip/driver/playbook/unixbench/clean.yaml
new file mode 100644
index 00000000..a7cb2540
--- /dev/null
+++ b/qtip/driver/playbook/unixbench/clean.yaml
@@ -0,0 +1,25 @@
+##############################################################################
+# Copyright (c) 2017 ZTE Corporation and others.
+# zhihui.wu1@zte.com.cn
+# 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
+##############################################################################
+
+- hosts: hosts
+ become: yes
+ remote_user: root
+
+ tasks:
+ - name: Cleaning tempT
+ file:
+ path: '{{ ansible_env.HOME }}/tempT'
+ state: absent
+
+ - name: Cleaning qtip_result
+ file:
+ path: '{{ ansible_env.HOME }}/qtip_result'
+ state: absent
+
+
diff --git a/qtip/driver/playbook/unixbench/dhrystone.yaml b/qtip/driver/playbook/unixbench/dhrystone.yaml
new file mode 100644
index 00000000..a0ee89a3
--- /dev/null
+++ b/qtip/driver/playbook/unixbench/dhrystone.yaml
@@ -0,0 +1,41 @@
+##############################################################################
+# Copyright (c) 2017 ZTE Corporation and others.
+# zhihui.wu1@zte.com.cn
+# 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: Make dhrystone directories
+ file:
+ path: '{{ ansible_env.HOME }}/qtip_result/{{ ansible_hostname }}/dhrystone/'
+ state: directory
+
+- include: ../inxi.yaml
+ vars:
+ dest_path: '{{ ansible_env.HOME }}/qtip_result/{{ ansible_hostname }}/dhrystone/'
+
+- include: ../top.yaml
+ vars:
+ dest_path: '{{ ansible_env.HOME }}/qtip_result/{{ ansible_hostname }}/dhrystone/'
+
+- name: Run dhrystone
+ shell: ./Run -v dhrystone
+ args:
+ chdir: '{{ ansible_env.HOME }}/tempT/UnixBench/'
+
+- name: Copying result to qtip result directory
+ shell: '{{ item }}'
+ with_items:
+ - mv ~/tempT/UnixBench/results/*.log ./
+ - mv ~/tempT/UnixBench/results/*.html ./
+ - mv ~/tempT/UnixBench/results/* ./dhrystone
+ args:
+ chdir: '{{ ansible_env.HOME }}/qtip_result/{{ ansible_hostname }}/dhrystone/'
+
+- name: Fetch dhrystone result files to local manchine
+ synchronize:
+ mode: pull
+ src: '{{ ansible_env.HOME }}/qtip_result/'
+ dest: '{{ result_dir }}/'
diff --git a/qtip/driver/playbook/unixbench/run.yaml b/qtip/driver/playbook/unixbench/run.yaml
new file mode 100644
index 00000000..fbe4d4ad
--- /dev/null
+++ b/qtip/driver/playbook/unixbench/run.yaml
@@ -0,0 +1,23 @@
+##############################################################################
+# Copyright (c) 2017 ZTE Corporation and others.
+# zhihui.wu1@zte.com.cn
+# 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
+##############################################################################
+
+- hosts: hosts
+ become: yes
+ remote_user: root
+
+ tasks:
+ - set_fact:
+ is_dhrystone: "{{ dhrystone | default(False) }}"
+ is_whetstone: "{{ whetstone | default(False) }}"
+
+ - include: ./dhrystone.yaml
+ when: "{{ is_dhrystone }}"
+
+ - include: ./whetstone.yaml
+ when: "{{ is_whetstone }}" \ No newline at end of file
diff --git a/qtip/driver/playbook/unixbench/setup.yaml b/qtip/driver/playbook/unixbench/setup.yaml
new file mode 100644
index 00000000..4b9b5240
--- /dev/null
+++ b/qtip/driver/playbook/unixbench/setup.yaml
@@ -0,0 +1,65 @@
+#############################################################################
+# Copyright (c) 2017 ZTE Corporation and others.
+# zhihui.wu1@zte.com.cn
+# 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
+#############################################################################
+
+- hosts: localhost
+ connection: local
+ gather_facts: no
+
+ tasks:
+ - name: Making dhrystone directory
+ file:
+ path: '{{ result_dir }}/'
+ state: directory
+
+- hosts: hosts
+ become: yes
+ remote_user: root
+
+ tasks:
+ - name: Cleaning tempT directory
+ file:
+ path: '{{ ansible_env.HOME }}/tempT'
+ state: absent
+
+ - name: Cleaning qtip_result directory
+ file:
+ path: '{{ ansible_env.HOME }}/qtip_result'
+ state: absent
+
+ - include: ../prepare_env.yaml
+
+ - name: Installing UnixBench dependencies if CentOS
+ yum:
+ name: '{{ item }}'
+ state: present
+ when: ansible_os_family == "RedHat"
+ with_items:
+ - git
+ - gcc
+ - patch
+ - perl-Time-HiRes
+
+ - name: Installing UnixBench dependencies if Ubuntu
+ apt:
+ name: '{{ item }}'
+ state: present
+ when: ansible_os_family == "Debian"
+ with_items:
+ - git
+ - gcc
+ - patch
+ - perl
+
+ - name: Clone UnixBench
+ git:
+ repo: https://github.com/kdlucas/byte-unixbench.git
+ dest: '{{ ansible_env.HOME }}/tempT/'
+
+ - name: Make UnixBench
+ shell: make --directory $HOME/tempT/UnixBench/ \ No newline at end of file
diff --git a/qtip/driver/playbook/unixbench/whetstone.yaml b/qtip/driver/playbook/unixbench/whetstone.yaml
new file mode 100644
index 00000000..c753779f
--- /dev/null
+++ b/qtip/driver/playbook/unixbench/whetstone.yaml
@@ -0,0 +1,41 @@
+##############################################################################
+# Copyright (c) 2017 ZTE Corporation and others.
+# zhihui.wu1@zte.com.cn
+# 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: Make whetstone directories
+ file:
+ path: '{{ ansible_env.HOME }}/qtip_result/{{ ansible_hostname }}/whetstone/'
+ state: directory
+
+- include: ../inxi.yaml
+ vars:
+ dest_path: '{{ ansible_env.HOME }}/qtip_result/{{ ansible_hostname }}/whetstone/'
+
+- include: ../top.yaml
+ vars:
+ dest_path: '{{ ansible_env.HOME }}/qtip_result/{{ ansible_hostname }}/whetstone/'
+
+- name: Run whetstone
+ shell: ./Run -v whetstone
+ args:
+ chdir: '{{ ansible_env.HOME }}/tempT/UnixBench/'
+
+- name: Copying result to qtip result directory
+ shell: '{{ item }}'
+ with_items:
+ - mv ~/tempT/UnixBench/results/*.log ./
+ - mv ~/tempT/UnixBench/results/*.html ./
+ - mv ~/tempT/UnixBench/results/* ./whetstone
+ args:
+ chdir: '{{ ansible_env.HOME }}/qtip_result/{{ ansible_hostname }}/whetstone/'
+
+- name: Fetch whetstone result files to local manchine
+ synchronize:
+ mode: pull
+ src: '{{ ansible_env.HOME }}/qtip_result/'
+ dest: '{{ result_dir }}/'
diff --git a/qtip/loader/file.py b/qtip/loader/file.py
index 038f57dd..a39e15f6 100644
--- a/qtip/loader/file.py
+++ b/qtip/loader/file.py
@@ -28,11 +28,12 @@ class FileLoader(BaseLoader):
self._filename = name
self.abspath = self.find(name, paths=paths)
- def find(self, name, paths=None):
+ @classmethod
+ def find(cls, name, paths=None):
"""find a specification in searching paths"""
- paths = [self.abspath] if paths is None else paths
+ paths = cls._paths if paths is None else paths
for p in paths:
- abspath = path.join(p, self.RELATIVE_PATH, name)
+ abspath = path.join(p, cls.RELATIVE_PATH, name)
if path.exists(abspath):
return abspath
raise NotFoundError(name, paths)
diff --git a/qtip/reporter/console.py b/qtip/reporter/console.py
new file mode 100644
index 00000000..64d677ba
--- /dev/null
+++ b/qtip/reporter/console.py
@@ -0,0 +1,46 @@
+##############################################################################
+# Copyright (c) 2017 taseer94@gmail.com 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 glob
+import json
+from os import path
+
+from jinja2 import Environment
+from jinja2 import FileSystemLoader
+from qtip.base import BaseActor
+
+ROOT_DIR = path.join(path.dirname(__file__), path.pardir, path.pardir)
+
+
+class ConsoleReporter(BaseActor):
+ """ report benchmark result to console """
+
+ def __init__(self, config, parent=None):
+ super(ConsoleReporter, self).__init__(config, parent=parent)
+
+ # TODO (taseer) load template from config
+ tpl_path = path.join(path.dirname(__file__), 'templates')
+ tpl_loader = FileSystemLoader(tpl_path)
+ self._env = Environment(loader=tpl_loader)
+ self.result_path = path.join(ROOT_DIR, 'collector')
+
+ def load_result(self):
+ # TODO (taseer) change result directory format more suitable to filter out
+ result_dirs = glob.glob('{}/20*'.format(self.result_path))
+ # select the last (latest) directory for rendering report, result_dirs[-1]
+ with open(path.join(self.result_path, result_dirs[-1], 'result.json')) as sample:
+ result = json.load(sample)
+ return result
+
+ def render(self, metric):
+ template = self._env.get_template('base.j2')
+ var_dict = self.load_result()
+ var_dict['metric_name'] = metric
+ out = template.render(var_dict)
+ return out
diff --git a/qtip/reporter/templates/base.j2 b/qtip/reporter/templates/base.j2
new file mode 100644
index 00000000..12a27536
--- /dev/null
+++ b/qtip/reporter/templates/base.j2
@@ -0,0 +1,25 @@
+Plan Name: {{ plan_name }}
+Start Time: {{ start_time }}
+Stop Time: {{ stop_time }}
+{%- for sys in sut -%}
+{% for qpi in sys.qpis %}
+{% for bm in qpi.benchmarks %}
+{%- if bm.name == metric_name -%}
+{%- if metric_name == 'dhrystone' or metric_name == 'whetstone' -%}
+{# TODO (taseer) remove hardcoded material #}
+{% include 'unixbench.j2' %}
+{% else %}
+{% include '%s.j2' % metric_name %}
+{% endif %}
+System Information:
+ CPU Brand: {{ bm.sysinfo.cpu }}
+ Disk: {{ bm.sysinfo.disk }}
+ Host Name: {{ bm.sysinfo.hostname }}
+ Kernel: {{ bm.sysinfo.kernel }}
+ Memory: {{ bm.sysinfo.memory }}
+ Operating System: {{ bm.sysinfo.os }}
+ Product: {{ bm.sysinfo.product }}
+{%- endif -%}
+{%- endfor -%}
+{%- endfor -%}
+{%- endfor -%}
diff --git a/qtip/reporter/templates/dpi.j2 b/qtip/reporter/templates/dpi.j2
new file mode 100644
index 00000000..758a821e
--- /dev/null
+++ b/qtip/reporter/templates/dpi.j2
@@ -0,0 +1,5 @@
+Benchmark: {{ bm.name }}
+CPU Usage: {{ bm. cpu_usage }}
+Results:
+ Bits per Second: {{ bm.results.bps }}
+ Packets per Second: {{ bm.results.pps }} \ No newline at end of file
diff --git a/qtip/reporter/templates/ramspeed.j2 b/qtip/reporter/templates/ramspeed.j2
new file mode 100644
index 00000000..d08d7e2e
--- /dev/null
+++ b/qtip/reporter/templates/ramspeed.j2
@@ -0,0 +1,13 @@
+Benchmark: {{ bm.name }}
+CPU Usage: {{ bm. cpu_usage }}
+Results:
+ Float Addition: {{ bm.results.float_add }}
+ Float Average: {{ bm.results.float_average }}
+ Float Copy: {{ bm.results.float_copy }}
+ Float Scale: {{ bm.results.float_scale }}
+ Float Triad: {{ bm.results.float_triad }}
+ Integer Addition: {{ bm.results.integer_add }}
+ Integer Average: {{ bm.results.integer_average }}
+ Integer Copy: {{ bm.results.integer_copy}}
+ Integer Scale: {{ bm.results.integer_scale }}
+ Integer Triad: {{ bm.results.integer_triad}} \ No newline at end of file
diff --git a/qtip/reporter/templates/ssl.j2 b/qtip/reporter/templates/ssl.j2
new file mode 100644
index 00000000..b46927a8
--- /dev/null
+++ b/qtip/reporter/templates/ssl.j2
@@ -0,0 +1,21 @@
+Benchmark: {{ bm.name }}
+CPU Usage: {{ bm.cpu_usage }}
+Results:
+ AES 128 CBC (bytes):
+ 16: {{ bm.results.aes_128_cbc_16_bytes }}
+ 64: {{ bm.results.aes_128_cbc_64_bytes }}
+ 256: {{ bm.results.aes_128_cbc_256_bytes }}
+ 1024: {{ bm.results.aes_128_cbc_1024_bytes }}
+ 8192: {{ bm.results.aes_128_cbc_8192_bytes }}
+
+ RSA SIGN:
+ 512: {{ bm.results.rsa_sign_512 }}
+ 1024: {{ bm.results.rsa_sign_1024 }}
+ 2048: {{ bm.results.rsa_sign_2048 }}
+ 4096: {{ bm.results.rsa_sign_4096 }}
+
+ RSA VERIFY:
+ 512: {{ bm.results.rsa_verify_512 }}
+ 1024: {{ bm.results.rsa_verify_1024 }}
+ 2048: {{ bm.results.rsa_verify_2048 }}
+ 4096: {{ bm.results.rsa_verify_4096 }} \ No newline at end of file
diff --git a/qtip/reporter/console/timeline.j2 b/qtip/reporter/templates/timeline.j2
index 9c18a996..ccb089e0 100644
--- a/qtip/reporter/console/timeline.j2
+++ b/qtip/reporter/templates/timeline.j2
@@ -1,8 +1,8 @@
-{% title %}
+{{ title }}
{% for phase in phases %}
-{{ phase.name|upper }}{{ "TIME" }}
+{{ phase.name|upper }}{{ "TIME"}}
{% for cp in phase.checkpoints %}
-{{ cp.name }}{{ cp.timestamp}}
+{{ cp.name }}{{ cp.timestamp| indent(15, True)}}
{% endfor %}
{% endfor %}
Total: {{ total }}
diff --git a/qtip/reporter/templates/unixbench.j2 b/qtip/reporter/templates/unixbench.j2
new file mode 100644
index 00000000..69006da7
--- /dev/null
+++ b/qtip/reporter/templates/unixbench.j2
@@ -0,0 +1,10 @@
+Benchmark: {{ bm.name }}
+CPU Usage: {{ bm. cpu_usage }}
+Results:
+ Multi CPU:
+ Number: {{ bm.results.multi_cpus.num }}
+ Score: {{ bm.results.multi_cpus.score }}
+ Single CPU:
+ Number: {{ bm.results.single_cpu.num }}
+ Score: {{ bm.results.single_cpu.num }}
+ Total CPUs: {{ bm.results.total_cpus }} \ No newline at end of file
diff --git a/qtip/runner/__init__.py b/qtip/runner/__init__.py
index 52c43a14..e69de29b 100644
--- a/qtip/runner/__init__.py
+++ b/qtip/runner/__init__.py
@@ -1,43 +0,0 @@
-##############################################################################
-# Copyright (c) 2016 ZTE Corp 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 qtip.base.constant import PkgName, BaseProp
-from qtip.base.error import NotFoundError
-from qtip.collector.stdout import StdoutCollector
-from qtip.driver.random import RandomDriver
-from qtip.reporter.console import ConsoleReporter
-
-
-class Runner(object):
- def __init__(self, spec, config=None):
- if config is None:
- config = spec[BaseProp.CONFIG]
-
- driver_name = config[BaseProp.DRIVER]
- collector_name = config[BaseProp.COLLECTOR]
- reporter_name = config[BaseProp.REPORTER]
-
- # TODO(yujunz) dynamically load modules by name
-
- if driver_name == 'random':
- self.driver = RandomDriver()
- else:
- raise NotFoundError(driver_name, heystack=PkgName.DRIVER)
-
- if collector_name == 'stdout':
- self.collector = StdoutCollector()
- else:
- raise NotFoundError(collector_name,
- heystack=PkgName.COLLECTOR)
-
- if reporter_name == 'console':
- self.reporter = ConsoleReporter()
- else:
- raise NotFoundError(reporter_name,
- heystack=PkgName.REPORTER)
diff --git a/qtip/reporter/base.py b/qtip/runner/base.py
index b931d14d..a86626d9 100644
--- a/qtip/reporter/base.py
+++ b/qtip/runner/base.py
@@ -8,7 +8,5 @@
##############################################################################
-class BaseReporter(object):
- """benchmark result reporter"""
- def __init__(self, collector=None):
- self.collector = collector
+class BaseRunner(object):
+ """benchmark task runner"""
diff --git a/qtip/runner/runner.py b/qtip/runner/runner.py
new file mode 100644
index 00000000..8bdbfb78
--- /dev/null
+++ b/qtip/runner/runner.py
@@ -0,0 +1,107 @@
+##############################################################################
+# Copyright (c) 2017 ZTE corp. 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 argparse
+import json
+import os
+from os import path
+import sys
+import time
+
+from qtip.collector.parser import grep
+from qtip.driver.ansible_driver import AnsibleDriver
+from qtip.util.logger import QtipLogger
+
+logger = QtipLogger('runner').get
+
+ALL_BENCHMARKS = ['dpi', 'ramspeed', 'ssl', 'dhrystone', 'whetstone']
+
+
+def parse_args(args):
+ parser = argparse.ArgumentParser()
+ parser.add_argument('-d', '--dest', required=True,
+ help='the destination where results will be stored.')
+ parser.add_argument('-b', '--benchmark', required=True, action='append',
+ help='the benchmark you want to execute.')
+ return parser.parse_args(args)
+
+
+def run_benchmark(result_dir, benchmarks):
+ if not path.isdir(result_dir):
+ os.makedirs(result_dir)
+ driver = AnsibleDriver({'args': {'result_dir': result_dir}})
+ driver.pre_run()
+ result = driver.run(benchmarks)
+ driver.cleanup()
+ return result
+
+
+def generate_report(result_dir, start_time, stop_time):
+ output = {
+ "plan_name": "compute_qpi",
+ "start_time": start_time,
+ "stop_time": stop_time,
+ "sut": []
+ }
+ output.update(parse_result(result_dir))
+ output.update({'stop_time': stop_time})
+ with open('{0}/result.json'.format(result_dir), 'w+') as f:
+ json.dump(output, f, indent=4, sort_keys=True)
+
+
+def parse_result(result_dir):
+ sut_template = {'sut': []}
+ nodes_list = os.listdir(result_dir)
+ for node in nodes_list:
+ node_output_template = {
+ 'name': node,
+ 'type': 'baremetal',
+ 'qpis': []
+ }
+ qpi_result = {'name': 'compute_qpi', 'benchmarks': []}
+ for benchmark in os.listdir('{0}/{1}'.format(result_dir, node)):
+ benchmark_result = \
+ grep.parse_benchmark_result(
+ '{0}/{1}/{2}'.format(result_dir, node, benchmark))
+ qpi_result['benchmarks'].append(benchmark_result)
+ node_output_template['qpis'].append(qpi_result)
+ sut_template['sut'].append(node_output_template)
+ return sut_template
+
+
+def main(args=sys.argv[1:]):
+ args = parse_args(args)
+
+ if not path.isdir(str(args.dest)):
+ logger.error("The destination {0} you give doesn't exist. "
+ "Please check!".format(args.dest))
+ sys.exit(1)
+
+ if args.benchmark == ['all']:
+ args.benchmark = ALL_BENCHMARKS
+ elif len(set(args.benchmark).difference(ALL_BENCHMARKS)) != 0:
+ logger.error("Please check benchmarks name. The supported benchmarks are"
+ "{0}".format(ALL_BENCHMARKS))
+ logger.info("Start to run benchmark test: {0}.".format(args.benchmark))
+
+ start_time = time.strftime("%Y-%m-%d-%H-%M")
+ logger.info("start_time: {0}".format(start_time))
+ if not args.dest.endswith('/'):
+ args.dest += '/'
+ result_dir = args.dest + start_time
+ ansible_result = run_benchmark(result_dir, args.benchmark)
+ stop_time = time.strftime("%Y-%m-%d-%H-%M")
+ logger.info("stop_time: {0}".format(stop_time))
+ if not ansible_result:
+ logger.error("Bechmarks run failed. Cann't generate any report.")
+ sys.exit(1)
+ generate_report(result_dir, start_time, stop_time)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/qtip/scripts/cleanup_creds.sh b/qtip/scripts/cleanup_creds.sh
new file mode 100755
index 00000000..ad66ba95
--- /dev/null
+++ b/qtip/scripts/cleanup_creds.sh
@@ -0,0 +1,20 @@
+#! /bin/bash
+##############################################################################
+# Copyright (c) 2017 ZTE corp. 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
+##############################################################################
+
+DEST_IP=$1
+PRIVATE_KEY=$2
+PUBLIC_KEY=$3
+sshoptions="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"
+
+case "$INSTALLER_TYPE" in
+ fuel)
+ ssh $sshoptions -i $PRIVATE_KEY root@$DEST_IP "sed -i '/$PUBLIC_KEY/d' /root/.ssh/authorized_keys"
+ ;;
+esac
diff --git a/qtip/scripts/fetch_compute_ips.sh b/qtip/scripts/generate_host_file.sh
index a2618ec9..ecc4d55f 100755
--- a/qtip/scripts/fetch_compute_ips.sh
+++ b/qtip/scripts/generate_host_file.sh
@@ -10,17 +10,15 @@
usage(){
- echo "usage: $0 [-v] -i <installer_type> -a <installer_ip>" >&2
- echo "[-v] Virtualized deployment" >&2
+ echo "usage: $0 -t <installer_type> -i <installer_ipaddr> -d <dest_hostfile>" >&2
}
info() {
- logger -s -t "fetch_compute_info.info" "$*"
+ logger -s -t "generate_host_file.info" "$*"
}
-
error() {
- logger -s -t "fetch_compute_info.error" "$*"
+ logger -s -t "generate_host_file.error" "$*"
exit 1
}
@@ -40,11 +38,11 @@ verify_connectivity(){
:${DEPLOY_TYPE:=''}
#Getoptions
-while getopts ":i:a:h:v" optchar; do
+while getopts ":t:i:d:" optchar; do
case "${optchar}" in
- i) installer_type=${OPTARG} ;;
- a) installer_ip=${OPTARG} ;;
- v) DEPLOY_TYPE="virt" ;;
+ t) installer_type=${OPTARG} ;;
+ i) installer_ipaddr=${OPTARG} ;;
+ d) dest_hostfile=${OPTARG} ;;
*) echo "Non-option argument: '-${OPTARG}'" >&2
usage
exit 2
@@ -54,9 +52,9 @@ done
#set vars from env if not provided by user as options
installer_type=${installer_type:-$INSTALLER_TYPE}
-installer_ip=${installer_ip:-$INSTALLER_IP}
+installer_ipaddr=${installer_ipaddr:-$INSTALLER_IP}
-if [ -z $installer_type ] || [ -z $installer_ip ]; then
+if [ -z $installer_type ] || [ -z $installer_ipaddr ]; then
usage
exit 2
fi
@@ -65,9 +63,9 @@ ssh_options="-oUserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"
#Start fetching compute ip
if [ "$installer_type" == "fuel" ]; then
- verify_connectivity $installer_ip
+ verify_connectivity $installer_ipaddr
- env=$(sshpass -p r00tme ssh 2>/dev/null $ssh_options root@${installer_ip} \
+ env=$(sshpass -p r00tme ssh 2>/dev/null $ssh_options root@${installer_ipaddr} \
'fuel env'|grep operational|head -1|awk '{print $1}') &> /dev/null
if [ -z $env ]; then
error "No operational environment detected in Fuel"
@@ -75,7 +73,7 @@ if [ "$installer_type" == "fuel" ]; then
env_id="${FUEL_ENV:-$env}"
# Check if compute is alive (online='True')
- IPS=$(sshpass -p r00tme ssh 2>/dev/null $ssh_options root@${installer_ip} \
+ IPS=$(sshpass -p r00tme ssh 2>/dev/null $ssh_options root@${installer_ipaddr} \
"fuel node --env ${env_id} | grep compute | grep 'True\| 1' | awk -F\| '{print \$5}' " | \
sed 's/ //g') &> /dev/null
@@ -86,8 +84,8 @@ elif [ "$installer_type" == "apex" ]; then
elif [ "$installer_type" == "compass" ]; then
# need test
- verify_connectivity $installer_ip
- IPS=$(sshpass -p'root' ssh 2>/dev/null $ssh_options root@${installer_ip} \
+ verify_connectivity $installer_ipaddr
+ IPS=$(sshpass -p'root' ssh 2>/dev/null $ssh_options root@${installer_ipaddr} \
'mysql -ucompass -pcompass -Dcompass -e"select * from cluster;"' \
| awk -F"," '{for(i=1;i<NF;i++)if($i~/\"host[4-5]\"/) {print $(i+1);}}' \
| grep -oP "\d+.\d+.\d+.\d+")
@@ -108,10 +106,11 @@ if [ -z "$IPS" ]; then
error "The compute node $IPS are not up. Please check that the POD is correctly deployed."
else
echo "-------- all compute node ips: --------"
- rm $HOME/ips.log
- touch $HOME/ips.log
- echo "$IPS" > $HOME/qtip/ips.log
- echo $IPS
+ rm $dest_hostfile
+ touch $dest_hostfile
+ echo "[hosts]" >> $dest_hostfile
+ echo "$IPS" >> $dest_hostfile
+ cat $dest_hostfile
fi
exit 0
diff --git a/qtip/scripts/qtip_creds.sh b/qtip/scripts/qtip_creds.sh
index af051ac5..239c60c1 100755
--- a/qtip/scripts/qtip_creds.sh
+++ b/qtip/scripts/qtip_creds.sh
@@ -1,30 +1,34 @@
#! /bin/bash
DEST_IP=$1
+PRIVATE_KEY=$2
+PUBLIC_KEY=$2.pub
+KEYNAME=$(basename $PRIVATE_KEY)
+
echo $INSTALLER_TYPE
echo $INSTALLER_IP
sshoptions="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"
case "$INSTALLER_TYPE" in
apex)
- scp $sshoptions -i $APEX_KEY ./config/QtipKey.pub stack@$INSTALLER_IP:/home/stack
- scp $sshoptions -i $APEX_KEY ./config/QtipKey stack@$INSTALLER_IP:/home/stack
- ssh $sshoptions -i $APEX_KEY stack@$INSTALLER_IP "ssh-copy-id $sshoptions -i /home/stack/QtipKey.pub heat-admin@$DEST_IP && rm -rf /home/stack/QtipKey && rm -rf /home/stack/QtipKey.pub"
+ scp $sshoptions -i $APEX_KEY $PUBLIC_KEY stack@$INSTALLER_IP:/home/stack
+ scp $sshoptions -i $APEX_KEY $PRIVATE_KEY stack@$INSTALLER_IP:/home/stack
+ ssh $sshoptions -i $APEX_KEY stack@$INSTALLER_IP "ssh-copy-id $sshoptions -i /home/stack/$KEYNAME.pub heat-admin@$DEST_IP && rm -rf /home/stack/$KEYNAME && rm -rf /home/stack/$KEYNAME.pub"
;;
fuel)
PSWD="r00tme"
- sshpass -p $PSWD scp $sshoptions ./config/QtipKey.pub root@$INSTALLER_IP:/root
- sshpass -p $PSWD scp $sshoptions ./config/QtipKey root@$INSTALLER_IP:/root
+ sshpass -p $PSWD scp $sshoptions $PUBLIC_KEY root@$INSTALLER_IP:/root
+ sshpass -p $PSWD scp $sshoptions $PRIVATE_KEY root@$INSTALLER_IP:/root
sshpass -p $PSWD ssh $sshoptions root@$INSTALLER_IP "grep -q '\-F /dev/null ' /usr/bin/ssh-copy-id || sed -i 's/\(ssh -i.*$\)/\1\n -F \/dev\/null \\\/g' `which ssh-copy-id`"
- sshpass -p $PSWD ssh $sshoptions root@$INSTALLER_IP "ssh-copy-id $sshoptions -i /root/QtipKey root@$DEST_IP && rm -rf /root/QtipKey && rm -rf /root/QtipKey.pub"
+ sshpass -p $PSWD ssh $sshoptions root@$INSTALLER_IP "ssh-copy-id $sshoptions -i /root/$KEYNAME root@$DEST_IP && rm -rf /root/$KEYNAME && rm -rf /root/$KEYNAME.pub"
;;
compass)
PSWD="root"
- sshpass -p $PSWD scp $sshoptions ./config/QtipKey.pub root@$INSTALLER_IP:/root
- sshpass -p $PSWD scp $sshoptions ./config/QtipKey root@$INSTALLER_IP:/root
- sshpass -p $PSWD ssh $sshoptions root@$INSTALLER_IP "ssh-copy-id $sshoptions -i /root/QtipKey.pub root@$DEST_IP && rm -rf /root/QtipKey && rm -rf /root/QtipKey.pub"
+ sshpass -p $PSWD scp $sshoptions $PUBLIC_KEY root@$INSTALLER_IP:/root
+ sshpass -p $PSWD scp $sshoptions $PRIVATE_KEY root@$INSTALLER_IP:/root
+ sshpass -p $PSWD ssh $sshoptions root@$INSTALLER_IP "ssh-copy-id $sshoptions -i /root/$KEYNAME.pub root@$DEST_IP && rm -rf /root/$KEYNAME && rm -rf /root/$KEYNAME.pub"
;;
joid)
PSWD="joid";;
*)
echo "Unkown installer $INSTALLER_TYPE specified";;
-esac
+esac \ No newline at end of file
diff --git a/qtip/util/env.py b/qtip/util/env.py
index 4e7a31c7..9299f8c0 100644
--- a/qtip/util/env.py
+++ b/qtip/util/env.py
@@ -1,137 +1,213 @@
##############################################################################
-# Copyright (c) 2016 Dell Inc, ZTE and others.
+# Copyright (c) 2017 ZTE 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 collections import defaultdict
import os
-import paramiko
+from os import path
+import re
import socket
+import sys
import time
-from os import path
-from os.path import expanduser
-
-SCRIPT_DIR = path.join(path.dirname(__file__), path.pardir, 'scripts')
-CONFIG_DIR = path.join(path.dirname(__file__), path.pardir, path.pardir,
- 'config')
-PRIVATE_KEY = CONFIG_DIR + '/QtipKey'
-PUBLIC_KEY = CONFIG_DIR + '/QtipKey.pub'
-IPS_FILE = expanduser('~') + "/qtip/ips.log"
-HOST_FILE = CONFIG_DIR + "/host"
-
-
-def fetch_compute_ips_via_installer():
- clean_file(IPS_FILE)
-
- installer_type = str(os.environ['INSTALLER_TYPE'].lower())
- installer_ip = str(os.environ['INSTALLER_IP'])
- if installer_type not in ["fuel"]:
- raise RuntimeError("%s is not supported" % installer_type)
- if not installer_ip:
- raise RuntimeError("undefine environment variable INSTALLER_IP")
-
- cmd = "bash %s/fetch_compute_ips.sh -i %s -a %s" % \
- (SCRIPT_DIR, installer_type, installer_ip)
- os.system(cmd)
- if path.isfile(IPS_FILE):
- return True
- else:
- return False
+import paramiko
-def parse_ips():
- ip_list = []
- with open(IPS_FILE, "r") as outfile:
- data = outfile.read()
- if data:
- ip_list.extend(data.rstrip('\n').split('\n'))
- return ip_list
+from qtip.util.logger import QtipLogger
+logger = QtipLogger('env').get
-def ssh_test(ip):
- os.system('ssh-keyscan %s >> /root/.ssh/known_hosts' % ip)
- time.sleep(2)
+SCRIPT_DIR = path.join(path.dirname(__file__), path.pardir, 'scripts')
+KEYNAME = 'QtipKey'
+PRIVATE_KEY = '{0}/qtip/{1}'.format(os.environ['HOME'], KEYNAME)
+PUBLIC_KEY = PRIVATE_KEY + '.pub'
+HOST_FILE = '{0}/qtip/hosts'.format(os.environ['HOME'])
- ssh_cmd = '%s/qtip_creds.sh %s' % (SCRIPT_DIR, ip)
- os.system(ssh_cmd)
- ssh = paramiko.SSHClient()
- ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
- ssh.connect(ip, key_filename='{0}/QtipKey'.format(CONFIG_DIR))
+def all_files_exist(*files):
+ if len(files) == 0:
+ return False
+ flag = True
+ for f_item in files:
+ flag &= path.isfile(f_item)
+ logger.info("Is {0} existed: {1}".format(f_item, flag))
+ return flag
- for attempts in range(100):
- try:
- stdin, stdout, stderr = ssh.exec_command('uname')
- if not stderr.readlines():
- print("{0}: SSH test successful")
- return True
- except socket.error:
- if attempts == 99:
- return False
- time.sleep(2)
+def clean_file(*files):
+ if len(files) == 0:
+ logger.info('Nothing to clean')
+ return False
-def ping_test(ip, attempts=30):
- ping_cmd = 'ping -D -c1 {0}'.format(ip)
- for i in range(attempts):
- if os.system(ping_cmd):
- print('\nWaiting for machine\n')
- time.sleep(10)
- else:
- print('\n\n %s is UP \n\n ' % ip)
+ def clean(f):
+ try:
+ if all_files_exist(f):
+ os.remove(f)
+ logger.info("Removed: {0}".format(f))
+ else:
+ logger.info("Not exists: {0}".format(f))
return True
- if i == 29:
+ except OSError as error:
+ logger.error("Not able to Remove: {0}".format(f), error)
return False
+ results = map(clean, files)
+ return len(results) == len(files) and False not in results
-def check_nodes_connectivity():
- ip_list = parse_ips()
- for ip in ip_list:
- if not ping_test(ip):
- raise RuntimeError("{0}: Ping test failed".format(ip))
- if not ssh_test(ip):
- raise RuntimeError("{0}: SSH test failed".format(ip))
+class AnsibleEnvSetup(object):
+ def __init__(self):
+ self.keypair = defaultdict(str)
+ self.hostfile = None
+ self.host_ip_list = []
-def generate_host_file():
- ip_list = parse_ips()
- with open(HOST_FILE, 'w') as host_file:
- for index, item in enumerate(ip_list):
- host_file.write("[host_{0}]\n".format(index))
- host_file.write(item + '\n')
-
-
-def generate_keypair():
- """Generating ssh keypair"""
- if not clean_keypair():
- raise RuntimeError("Cann't remove old keypair")
-
- cmd = "ssh-keygen -t rsa -N "" -f {0} -q".format(PRIVATE_KEY)
- os.system(cmd)
-
- if path.isfile(PRIVATE_KEY) and path.isfile(PUBLIC_KEY):
- return True
- else:
- return False
+ def setup(self, config={}):
+ try:
+ if 'hostfile' in config:
+ self.check_hostfile(config['hostfile'])
+ else:
+ self.generate_default_hostfile()
+ self.fetch_host_ip_from_hostfile()
+ if 'keypair' in config:
+ self.check_keypair(config['keypair'])
+ else:
+ self.generate_default_keypair()
+ self.pass_keypair_to_remote()
+ self.check_hosts_ssh_connectivity()
+ except Exception as error:
+ logger.info(error)
+ sys.exit(1)
+
+ def check_keypair(self, keypair):
+ self.keypair = defaultdict(str)
+ if all_files_exist(keypair, '{0}.pub'.format(keypair)):
+ self.keypair['private'] = keypair
+ self.keypair['public'] = '{0}.pub'.format(keypair)
+ else:
+ raise RuntimeError("The keypairs you in the configuration file"
+ " is invalid or not existed.")
+
+ def generate_default_keypair(self):
+ if not all_files_exist(PRIVATE_KEY, PUBLIC_KEY):
+ logger.info("Generate default keypair {0} under "
+ "{1}".format(KEYNAME, os.environ['HOME']))
+ cmd = '''ssh-keygen -t rsa -N "" -f {0} -q -b 2048
+ -C qtip@insecure'''.format(PRIVATE_KEY)
+ os.system(cmd)
+ self.keypair['private'] = PRIVATE_KEY
+ self.keypair['public'] = PUBLIC_KEY
+
+ def pass_keypair_to_remote(self):
+ results = map(lambda ip: self._pass_keypair(ip, self.keypair['private']),
+ self.host_ip_list)
+
+ if not (len(results) == len(self.host_ip_list) and False not in results):
+ raise RuntimeError("Failed on passing keypair to remote.")
+
+ @staticmethod
+ def _pass_keypair(ip, private_key):
+ try:
+ os.system('ssh-keyscan %s >> /root/.ssh/known_hosts' % ip)
+ time.sleep(2)
+ ssh_cmd = '%s/qtip_creds.sh %s %s' % (SCRIPT_DIR, ip, private_key)
+ os.system(ssh_cmd)
+ logger.info('Pass keypair to remote hosts {0} successfully'.format(ip))
+ return True
+ except Exception as error:
+ logger.error(error)
+ return False
+ def check_hostfile(self, hostfile):
+ if all_files_exist(hostfile):
+ self.hostfile = hostfile
+ else:
+ raise RuntimeError(
+ "The hostfile {0} is invalid or not existed.".format(hostfile))
-def clean_file(file_path):
- try:
- if path.isfile(file_path):
- os.remove(file_path)
- print("Removed: " + file_path)
+ def generate_default_hostfile(self):
+ try:
+ # check whether the file is already existed
+ self.check_hostfile(HOST_FILE)
+ except Exception:
+ logger.info("Generate default hostfile {0} under "
+ "{1}".format(HOST_FILE, os.environ['HOME']))
+ self._generate_hostfile_via_installer()
+
+ def _generate_hostfile_via_installer(self):
+ self.hostfile = None
+
+ installer_type = str(os.environ['INSTALLER_TYPE'].lower())
+ installer_ip = str(os.environ['INSTALLER_IP'])
+
+ if installer_type not in ["fuel"]:
+ raise ValueError("{0} is not supported".format(installer_type))
+ if not installer_ip:
+ raise ValueError(
+ "The value of environment variable INSTALLER_IP is empty.")
+
+ cmd = "bash %s/generate_host_file.sh -t %s -i %s -d %s" % \
+ (SCRIPT_DIR, installer_type, installer_ip, HOST_FILE)
+ os.system(cmd)
+
+ self.hostfile = HOST_FILE
+
+ def fetch_host_ip_from_hostfile(self):
+ self.host_ip_list = []
+ logger.info('Fetch host ips from hostfile...')
+ with open(self.hostfile, 'r') as f:
+ self.host_ip_list = re.findall('\d+.\d+.\d+.\d+', f.read())
+ if self.host_ip_list:
+ logger.info("The remote compute nodes: {0}".format(self.host_ip_list))
else:
- print("Not exists: " + file_path)
- except OSError, error:
- print("Not able to Remove: " + file_path, error)
+ raise ValueError("The hostfile doesn't include host ip addresses.")
+
+ def check_hosts_ssh_connectivity(self):
+ results = map(lambda ip: self._ssh_is_ok(ip, self.keypair['private']),
+ self.host_ip_list)
+ if not (len(results) == len(self.host_ip_list) and False not in results):
+ raise RuntimeError("Failed on checking hosts ssh connectivity.")
+
+ @staticmethod
+ def _ssh_is_ok(ip, private_key, attempts=100):
+ logger.info('Check hosts {0} ssh connectivity...'.format(ip))
+ ssh = paramiko.SSHClient()
+ ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
+ ssh.connect(ip, key_filename=private_key)
+
+ for attempt in range(attempts):
+ try:
+ stdin, stdout, stderr = ssh.exec_command('uname')
+ if not stderr.readlines():
+ logger.info("{0}: SSH test successful.".format(ip))
+ return True
+ except socket.error:
+ logger.debug("%s times ssh test......failed." % str(attempt + 1))
+ if attempt == (attempts - 1):
+ return False
+ time.sleep(2)
return False
- return True
+ def cleanup(self):
+ CI_DEBUG = os.getenv('CI_DEBUG')
-def clean_keypair():
- flag = True
- flag &= clean_file(PRIVATE_KEY)
- flag &= clean_file(PUBLIC_KEY)
- return flag
+ if CI_DEBUG is not None and CI_DEBUG.lower() == 'true':
+ logger.info("DEBUG Mode: please do cleanup by manual.")
+ else:
+ with open(self.keypair['public'], 'r') as f:
+ key = f.read().strip('\n').replace('/', '\/')
+ if key:
+ for ip in self.host_ip_list:
+ logger.info("Cleanup authorized_keys from {0}...".format(ip))
+ cmd = '''bash {0}/cleanup_creds.sh {1} {2} "{3}"'''.format(
+ SCRIPT_DIR, ip, self.keypair['private'], key)
+ os.system(cmd)
+ else:
+ logger.error("Nothing in public key file.")
+
+ logger.info("Cleanup hostfile and keypair.")
+ clean_file(self.hostfile,
+ self.keypair['private'],
+ self.keypair['public'])
diff --git a/requirements.txt b/requirements.txt
index c51228f2..d00b3cf1 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -4,3 +4,5 @@ paramiko
connexion
numpy
pbr
+ConfigParser
+prettytable
diff --git a/setup.cfg b/setup.cfg
index 5b9b9567..23103fc5 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -14,11 +14,15 @@ setup-hooks =
[entry_points]
console_scripts =
qtip = qtip.cli.entry:cli
- # TODO(akhil) add qtip-api
+ qtip-api = qtip.api.__main__:main
[files]
packages =
qtip
+ benchmarks
+package_data =
+ benchmarks =
+ plan/*.*
data_files =
opt/qtip = opt/*
diff --git a/test-requirements.txt b/test-requirements.txt
index e434748e..cfbbdcdd 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -5,6 +5,7 @@
tox
pytest
pytest-cov
+pytest-mock
coverage
pykwalify
mock
diff --git a/tests/data/benchmarks/plan/compute.yaml b/tests/data/benchmarks/plan/compute.yaml
index 8529d8dc..f4a7a2dc 100644
--- a/tests/data/benchmarks/plan/compute.yaml
+++ b/tests/data/benchmarks/plan/compute.yaml
@@ -16,6 +16,80 @@ config:
collectors:
- type: logfile
paths:
+ - '../../external/dpi/'
+ logs:
+ - filename: dpi_dump.txt
+ parsers:
+ - type: grep
+ regex: |-
+ ^\s+nDPI throughput:.+?(?P<pps>\d+.\d+)\sM\spps.+
+ ?(?P<bps>\d+.\d+)\sGb\/sec
+ - type: logfile
+ paths:
+ - '../../external/ramspeed/'
+ logs:
+ - filename: Intmem
+ parsers:
+ - type: grep
+ regex: '^INTEGER\s+BatchRun\s+Copy:\s+?(?P<integer_copy>\d+\.\d+)\sMB/s$'
+ - type: grep
+ regex: '^INTEGER\s+BatchRun\s+Scale:\s+?(?P<integer_scale>\d+\.\d+)\sMB/s$'
+ - type: grep
+ regex: '^INTEGER\s+BatchRun\s+Add:\s+?(?P<integer_add>\d+\.\d+)\sMB/s$'
+ - type: grep
+ regex: '^INTEGER\s+BatchRun\s+Triad:\s+?(?P<integer_triad>\d+\.\d+)\sMB/s$'
+ - type: grep
+ regex: '^INTEGER\s+BatchRun\s+AVERAGE:\s+?(?P<integer_average>\d+\.\d+)\sMB/s$'
+ - filename: Floatmem
+ parsers:
+ - type: grep
+ regex: '^FL-POINT\s+BatchRun\s+Copy:\s+?(?P<float_copy>\d+\.\d+)\sMB/s$'
+ - type: grep
+ regex: '^FL-POINT\s+BatchRun\s+Scale:\s+?(?P<float_scale>\d+\.\d+)\sMB/s$'
+ - type: grep
+ regex: '^FL-POINT\s+BatchRun\s+Add:\s+?(?P<float_add>\d+\.\d+)\sMB/s$'
+ - type: grep
+ regex: '^FL-POINT\s+BatchRun\s+Triad:\s+?(?P<float_triad>\d+\.\d+)\sMB/s$'
+ - type: grep
+ regex: '^FL-POINT\s+BatchRun\s+AVERAGE:\s+?(?P<float_average>\d+\.\d+)\sMB/s$'
+ - type: logfile
+ paths:
+ - '../../external/ssl/'
+ logs:
+ - filename: RSA_dump
+ parsers:
+ - type: grep
+ regex: |-
+ ^rsa\s+512\sbits\s.+
+ ?(?P<rsa_sign_512>\d+\.\d)\s+
+ ?(?P<rsa_verify_512>\d+\.\d)$
+ - type: grep
+ regex: |-
+ ^rsa\s+1024\sbits\s.+
+ ?(?P<rsa_sign_1024>\d+\.\d)\s+
+ ?(?P<rsa_verify_1024>\d+\.\d)$
+ - type: grep
+ regex: |-
+ ^rsa\s+2048\sbits\s.+
+ ?(?P<rsa_sign_2048>\d+\.\d)\s+
+ ?(?P<rsa_verify_2048>\d+\.\d)$
+ - type: grep
+ regex: |-
+ ^rsa\s+4096\sbits\s.+
+ ?(?P<rsa_sign_4096>\d+\.\d)\s+
+ ?(?P<rsa_verify_4096>\d+\.\d)$
+ - filename: AES-128-CBC_dump
+ parsers:
+ - type: grep
+ regex: |-
+ ^aes-128-cbc\s+
+ ?(?P<aes_128_cbc_16_bytes>\d+\.\w+)\s+
+ ?(?P<aes_128_cbc_64_bytes>\d+\.\w+)\s+
+ ?(?P<aes_128_cbc_256_bytes>\d+\.\w+)\s+
+ ?(?P<aes_128_cbc_1024_bytes>\d+\.\w+)\s+
+ ?(?P<aes_128_cbc_8192_bytes>\d+\.\w+)$
+ - type: logfile
+ paths:
- '../../external/sysinfo'
logs:
- filename: top.log
diff --git a/qtip/driver/ansible/ansible.py b/tests/data/benchmarks/plan/sample.yaml
index cd17625d..04e8caf9 100644
--- a/qtip/driver/ansible/ansible.py
+++ b/tests/data/benchmarks/plan/sample.yaml
@@ -1,14 +1,14 @@
##############################################################################
-# Copyright (c) 2016 ZTE Corp and others.
+# 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
##############################################################################
-
-from qtip.driver.base import BaseDriver
-
-
-class AnsibleDriver(BaseDriver):
- """driver for running performance tests with Ansible"""
+name: sample
+description: sample benchmark plan for testing default path
+config:
+ collectors: []
+ reporters: []
+QPIs: []
diff --git a/tests/data/external/dpi/dpi_dump.txt b/tests/data/external/dpi/dpi_dump.txt
new file mode 100644
index 00000000..1f4e2839
--- /dev/null
+++ b/tests/data/external/dpi/dpi_dump.txt
@@ -0,0 +1,809 @@
+-----------------------------------------------------------
+* NOTE: This is demo app to show *some* nDPI features.
+* In this demo we have implemented only some basic features
+* just to show you what you can do with the library. Feel
+* free to extend it and send us the patches for inclusion
+------------------------------------------------------------
+
+Using nDPI (1.8.0-dev-707-6a27b62) [1 thread(s)]
+Reading packets from pcap file test.pcap...
+Running thread 0...
+
+nDPI Memory statistics:
+ nDPI Memory (once): 110.55 KB
+ Flow Memory (per flow): 1.95 KB
+ Actual Memory: 3.46 MB
+ Peak Memory: 3.46 MB
+
+Traffic statistics:
+ Ethernet bytes: 75948198 (includes ethernet CRC/IFC/trailer)
+ Discarded bytes: 55256
+ IP packets: 60265 of 61155 packets total
+ IP bytes: 74501838 (avg pkt size 1218 bytes)
+ Unique flows: 545
+ TCP Packets: 21188
+ UDP Packets: 39042
+ VLAN Packets: 0
+ MPLS Packets: 0
+ PPPoE Packets: 0
+ Fragmented Packets: 4
+ Max Packet size: 64260
+ Packet Len < 64: 30624
+ Packet Len 64-128: 1158
+ Packet Len 128-256: 674
+ Packet Len 256-1024: 817
+ Packet Len 1024-1500: 21924
+ Packet Len > 1500: 5068
+ nDPI throughput: 1.56 M pps / 14.62 Gb/sec
+ Traffic throughput: 228.03 pps / 2.19 Mb/sec
+ Traffic duration: 264.290 sec
+ Guessed flow protos: 9
+
+
+Detected protocols:
+ Unknown packets: 6126 bytes: 10913415 flows: 46
+ FTP_CONTROL packets: 42 bytes: 4384 flows: 1
+ DNS packets: 66 bytes: 6520 flows: 23
+ IPP packets: 46 bytes: 12059 flows: 1
+ HTTP packets: 377 bytes: 113616 flows: 24
+ MDNS packets: 43 bytes: 11742 flows: 9
+ NetBIOS packets: 48 bytes: 4754 flows: 12
+ SSDP packets: 101 bytes: 32533 flows: 21
+ DHCP packets: 21 bytes: 7346 flows: 2
+ BitTorrent packets: 37639 bytes: 29656716 flows: 65
+ ICMP packets: 15 bytes: 4956 flows: 5
+ IGMP packets: 10 bytes: 600 flows: 9
+ SSL packets: 1199 bytes: 622508 flows: 24
+ ICMPV6 packets: 2 bytes: 172 flows: 2
+ DHCPV6 packets: 1 bytes: 144 flows: 1
+ Facebook packets: 349 bytes: 206444 flows: 21
+ Twitter packets: 137 bytes: 45679 flows: 8
+ Dropbox packets: 155 bytes: 45358 flows: 12
+ GMail packets: 35 bytes: 10470 flows: 3
+ YouTube packets: 11721 bytes: 31050728 flows: 33
+ Skype packets: 237 bytes: 35082 flows: 30
+ Google packets: 558 bytes: 164639 flows: 52
+ WhatsApp packets: 969 bytes: 1477350 flows: 17
+ Viber packets: 60 bytes: 27602 flows: 1
+ LLMNR packets: 71 bytes: 5297 flows: 36
+ Amazon packets: 89 bytes: 23572 flows: 9
+ QUIC packets: 41 bytes: 3474 flows: 1
+ BJNP packets: 72 bytes: 4320 flows: 72
+ Microsoft packets: 35 bytes: 10358 flows: 5
+
+
+Protocol statistics:
+ Safe 632978 bytes
+ Acceptable 31693889 bytes
+ Fun 31257172 bytes
+ Unsafe 4384 bytes
+ Unrated 10913415 bytes
+
+-----------------------------------------------------------
+* NOTE: This is demo app to show *some* nDPI features.
+* In this demo we have implemented only some basic features
+* just to show you what you can do with the library. Feel
+* free to extend it and send us the patches for inclusion
+------------------------------------------------------------
+
+Using nDPI (1.8.0-dev-707-6a27b62) [1 thread(s)]
+Reading packets from pcap file test.pcap...
+Running thread 0...
+
+nDPI Memory statistics:
+ nDPI Memory (once): 110.55 KB
+ Flow Memory (per flow): 1.95 KB
+ Actual Memory: 3.46 MB
+ Peak Memory: 3.46 MB
+
+Traffic statistics:
+ Ethernet bytes: 75948198 (includes ethernet CRC/IFC/trailer)
+ Discarded bytes: 55256
+ IP packets: 60265 of 61155 packets total
+ IP bytes: 74501838 (avg pkt size 1218 bytes)
+ Unique flows: 545
+ TCP Packets: 21188
+ UDP Packets: 39042
+ VLAN Packets: 0
+ MPLS Packets: 0
+ PPPoE Packets: 0
+ Fragmented Packets: 4
+ Max Packet size: 64260
+ Packet Len < 64: 30624
+ Packet Len 64-128: 1158
+ Packet Len 128-256: 674
+ Packet Len 256-1024: 817
+ Packet Len 1024-1500: 21924
+ Packet Len > 1500: 5068
+ nDPI throughput: 1.31 M pps / 12.31 Gb/sec
+ Traffic throughput: 228.03 pps / 2.19 Mb/sec
+ Traffic duration: 264.290 sec
+ Guessed flow protos: 9
+
+
+Detected protocols:
+ Unknown packets: 6126 bytes: 10913415 flows: 46
+ FTP_CONTROL packets: 42 bytes: 4384 flows: 1
+ DNS packets: 66 bytes: 6520 flows: 23
+ IPP packets: 46 bytes: 12059 flows: 1
+ HTTP packets: 377 bytes: 113616 flows: 24
+ MDNS packets: 43 bytes: 11742 flows: 9
+ NetBIOS packets: 48 bytes: 4754 flows: 12
+ SSDP packets: 101 bytes: 32533 flows: 21
+ DHCP packets: 21 bytes: 7346 flows: 2
+ BitTorrent packets: 37639 bytes: 29656716 flows: 65
+ ICMP packets: 15 bytes: 4956 flows: 5
+ IGMP packets: 10 bytes: 600 flows: 9
+ SSL packets: 1199 bytes: 622508 flows: 24
+ ICMPV6 packets: 2 bytes: 172 flows: 2
+ DHCPV6 packets: 1 bytes: 144 flows: 1
+ Facebook packets: 349 bytes: 206444 flows: 21
+ Twitter packets: 137 bytes: 45679 flows: 8
+ Dropbox packets: 155 bytes: 45358 flows: 12
+ GMail packets: 35 bytes: 10470 flows: 3
+ YouTube packets: 11721 bytes: 31050728 flows: 33
+ Skype packets: 237 bytes: 35082 flows: 30
+ Google packets: 558 bytes: 164639 flows: 52
+ WhatsApp packets: 969 bytes: 1477350 flows: 17
+ Viber packets: 60 bytes: 27602 flows: 1
+ LLMNR packets: 71 bytes: 5297 flows: 36
+ Amazon packets: 89 bytes: 23572 flows: 9
+ QUIC packets: 41 bytes: 3474 flows: 1
+ BJNP packets: 72 bytes: 4320 flows: 72
+ Microsoft packets: 35 bytes: 10358 flows: 5
+
+
+Protocol statistics:
+ Safe 632978 bytes
+ Acceptable 31693889 bytes
+ Fun 31257172 bytes
+ Unsafe 4384 bytes
+ Unrated 10913415 bytes
+
+-----------------------------------------------------------
+* NOTE: This is demo app to show *some* nDPI features.
+* In this demo we have implemented only some basic features
+* just to show you what you can do with the library. Feel
+* free to extend it and send us the patches for inclusion
+------------------------------------------------------------
+
+Using nDPI (1.8.0-dev-707-6a27b62) [1 thread(s)]
+Reading packets from pcap file test.pcap...
+Running thread 0...
+
+nDPI Memory statistics:
+ nDPI Memory (once): 110.55 KB
+ Flow Memory (per flow): 1.95 KB
+ Actual Memory: 3.46 MB
+ Peak Memory: 3.46 MB
+
+Traffic statistics:
+ Ethernet bytes: 75948198 (includes ethernet CRC/IFC/trailer)
+ Discarded bytes: 55256
+ IP packets: 60265 of 61155 packets total
+ IP bytes: 74501838 (avg pkt size 1218 bytes)
+ Unique flows: 545
+ TCP Packets: 21188
+ UDP Packets: 39042
+ VLAN Packets: 0
+ MPLS Packets: 0
+ PPPoE Packets: 0
+ Fragmented Packets: 4
+ Max Packet size: 64260
+ Packet Len < 64: 30624
+ Packet Len 64-128: 1158
+ Packet Len 128-256: 674
+ Packet Len 256-1024: 817
+ Packet Len 1024-1500: 21924
+ Packet Len > 1500: 5068
+ nDPI throughput: 1.54 M pps / 14.45 Gb/sec
+ Traffic throughput: 228.03 pps / 2.19 Mb/sec
+ Traffic duration: 264.290 sec
+ Guessed flow protos: 9
+
+
+Detected protocols:
+ Unknown packets: 6126 bytes: 10913415 flows: 46
+ FTP_CONTROL packets: 42 bytes: 4384 flows: 1
+ DNS packets: 66 bytes: 6520 flows: 23
+ IPP packets: 46 bytes: 12059 flows: 1
+ HTTP packets: 377 bytes: 113616 flows: 24
+ MDNS packets: 43 bytes: 11742 flows: 9
+ NetBIOS packets: 48 bytes: 4754 flows: 12
+ SSDP packets: 101 bytes: 32533 flows: 21
+ DHCP packets: 21 bytes: 7346 flows: 2
+ BitTorrent packets: 37639 bytes: 29656716 flows: 65
+ ICMP packets: 15 bytes: 4956 flows: 5
+ IGMP packets: 10 bytes: 600 flows: 9
+ SSL packets: 1199 bytes: 622508 flows: 24
+ ICMPV6 packets: 2 bytes: 172 flows: 2
+ DHCPV6 packets: 1 bytes: 144 flows: 1
+ Facebook packets: 349 bytes: 206444 flows: 21
+ Twitter packets: 137 bytes: 45679 flows: 8
+ Dropbox packets: 155 bytes: 45358 flows: 12
+ GMail packets: 35 bytes: 10470 flows: 3
+ YouTube packets: 11721 bytes: 31050728 flows: 33
+ Skype packets: 237 bytes: 35082 flows: 30
+ Google packets: 558 bytes: 164639 flows: 52
+ WhatsApp packets: 969 bytes: 1477350 flows: 17
+ Viber packets: 60 bytes: 27602 flows: 1
+ LLMNR packets: 71 bytes: 5297 flows: 36
+ Amazon packets: 89 bytes: 23572 flows: 9
+ QUIC packets: 41 bytes: 3474 flows: 1
+ BJNP packets: 72 bytes: 4320 flows: 72
+ Microsoft packets: 35 bytes: 10358 flows: 5
+
+
+Protocol statistics:
+ Safe 632978 bytes
+ Acceptable 31693889 bytes
+ Fun 31257172 bytes
+ Unsafe 4384 bytes
+ Unrated 10913415 bytes
+
+-----------------------------------------------------------
+* NOTE: This is demo app to show *some* nDPI features.
+* In this demo we have implemented only some basic features
+* just to show you what you can do with the library. Feel
+* free to extend it and send us the patches for inclusion
+------------------------------------------------------------
+
+Using nDPI (1.8.0-dev-707-6a27b62) [1 thread(s)]
+Reading packets from pcap file test.pcap...
+Running thread 0...
+
+nDPI Memory statistics:
+ nDPI Memory (once): 110.55 KB
+ Flow Memory (per flow): 1.95 KB
+ Actual Memory: 3.46 MB
+ Peak Memory: 3.46 MB
+
+Traffic statistics:
+ Ethernet bytes: 75948198 (includes ethernet CRC/IFC/trailer)
+ Discarded bytes: 55256
+ IP packets: 60265 of 61155 packets total
+ IP bytes: 74501838 (avg pkt size 1218 bytes)
+ Unique flows: 545
+ TCP Packets: 21188
+ UDP Packets: 39042
+ VLAN Packets: 0
+ MPLS Packets: 0
+ PPPoE Packets: 0
+ Fragmented Packets: 4
+ Max Packet size: 64260
+ Packet Len < 64: 30624
+ Packet Len 64-128: 1158
+ Packet Len 128-256: 674
+ Packet Len 256-1024: 817
+ Packet Len 1024-1500: 21924
+ Packet Len > 1500: 5068
+ nDPI throughput: 1.35 M pps / 12.71 Gb/sec
+ Traffic throughput: 228.03 pps / 2.19 Mb/sec
+ Traffic duration: 264.290 sec
+ Guessed flow protos: 9
+
+
+Detected protocols:
+ Unknown packets: 6126 bytes: 10913415 flows: 46
+ FTP_CONTROL packets: 42 bytes: 4384 flows: 1
+ DNS packets: 66 bytes: 6520 flows: 23
+ IPP packets: 46 bytes: 12059 flows: 1
+ HTTP packets: 377 bytes: 113616 flows: 24
+ MDNS packets: 43 bytes: 11742 flows: 9
+ NetBIOS packets: 48 bytes: 4754 flows: 12
+ SSDP packets: 101 bytes: 32533 flows: 21
+ DHCP packets: 21 bytes: 7346 flows: 2
+ BitTorrent packets: 37639 bytes: 29656716 flows: 65
+ ICMP packets: 15 bytes: 4956 flows: 5
+ IGMP packets: 10 bytes: 600 flows: 9
+ SSL packets: 1199 bytes: 622508 flows: 24
+ ICMPV6 packets: 2 bytes: 172 flows: 2
+ DHCPV6 packets: 1 bytes: 144 flows: 1
+ Facebook packets: 349 bytes: 206444 flows: 21
+ Twitter packets: 137 bytes: 45679 flows: 8
+ Dropbox packets: 155 bytes: 45358 flows: 12
+ GMail packets: 35 bytes: 10470 flows: 3
+ YouTube packets: 11721 bytes: 31050728 flows: 33
+ Skype packets: 237 bytes: 35082 flows: 30
+ Google packets: 558 bytes: 164639 flows: 52
+ WhatsApp packets: 969 bytes: 1477350 flows: 17
+ Viber packets: 60 bytes: 27602 flows: 1
+ LLMNR packets: 71 bytes: 5297 flows: 36
+ Amazon packets: 89 bytes: 23572 flows: 9
+ QUIC packets: 41 bytes: 3474 flows: 1
+ BJNP packets: 72 bytes: 4320 flows: 72
+ Microsoft packets: 35 bytes: 10358 flows: 5
+
+
+Protocol statistics:
+ Safe 632978 bytes
+ Acceptable 31693889 bytes
+ Fun 31257172 bytes
+ Unsafe 4384 bytes
+ Unrated 10913415 bytes
+
+-----------------------------------------------------------
+* NOTE: This is demo app to show *some* nDPI features.
+* In this demo we have implemented only some basic features
+* just to show you what you can do with the library. Feel
+* free to extend it and send us the patches for inclusion
+------------------------------------------------------------
+
+Using nDPI (1.8.0-dev-707-6a27b62) [1 thread(s)]
+Reading packets from pcap file test.pcap...
+Running thread 0...
+
+nDPI Memory statistics:
+ nDPI Memory (once): 110.55 KB
+ Flow Memory (per flow): 1.95 KB
+ Actual Memory: 3.46 MB
+ Peak Memory: 3.46 MB
+
+Traffic statistics:
+ Ethernet bytes: 75948198 (includes ethernet CRC/IFC/trailer)
+ Discarded bytes: 55256
+ IP packets: 60265 of 61155 packets total
+ IP bytes: 74501838 (avg pkt size 1218 bytes)
+ Unique flows: 545
+ TCP Packets: 21188
+ UDP Packets: 39042
+ VLAN Packets: 0
+ MPLS Packets: 0
+ PPPoE Packets: 0
+ Fragmented Packets: 4
+ Max Packet size: 64260
+ Packet Len < 64: 30624
+ Packet Len 64-128: 1158
+ Packet Len 128-256: 674
+ Packet Len 256-1024: 817
+ Packet Len 1024-1500: 21924
+ Packet Len > 1500: 5068
+ nDPI throughput: 1.55 M pps / 14.53 Gb/sec
+ Traffic throughput: 228.03 pps / 2.19 Mb/sec
+ Traffic duration: 264.290 sec
+ Guessed flow protos: 9
+
+
+Detected protocols:
+ Unknown packets: 6126 bytes: 10913415 flows: 46
+ FTP_CONTROL packets: 42 bytes: 4384 flows: 1
+ DNS packets: 66 bytes: 6520 flows: 23
+ IPP packets: 46 bytes: 12059 flows: 1
+ HTTP packets: 377 bytes: 113616 flows: 24
+ MDNS packets: 43 bytes: 11742 flows: 9
+ NetBIOS packets: 48 bytes: 4754 flows: 12
+ SSDP packets: 101 bytes: 32533 flows: 21
+ DHCP packets: 21 bytes: 7346 flows: 2
+ BitTorrent packets: 37639 bytes: 29656716 flows: 65
+ ICMP packets: 15 bytes: 4956 flows: 5
+ IGMP packets: 10 bytes: 600 flows: 9
+ SSL packets: 1199 bytes: 622508 flows: 24
+ ICMPV6 packets: 2 bytes: 172 flows: 2
+ DHCPV6 packets: 1 bytes: 144 flows: 1
+ Facebook packets: 349 bytes: 206444 flows: 21
+ Twitter packets: 137 bytes: 45679 flows: 8
+ Dropbox packets: 155 bytes: 45358 flows: 12
+ GMail packets: 35 bytes: 10470 flows: 3
+ YouTube packets: 11721 bytes: 31050728 flows: 33
+ Skype packets: 237 bytes: 35082 flows: 30
+ Google packets: 558 bytes: 164639 flows: 52
+ WhatsApp packets: 969 bytes: 1477350 flows: 17
+ Viber packets: 60 bytes: 27602 flows: 1
+ LLMNR packets: 71 bytes: 5297 flows: 36
+ Amazon packets: 89 bytes: 23572 flows: 9
+ QUIC packets: 41 bytes: 3474 flows: 1
+ BJNP packets: 72 bytes: 4320 flows: 72
+ Microsoft packets: 35 bytes: 10358 flows: 5
+
+
+Protocol statistics:
+ Safe 632978 bytes
+ Acceptable 31693889 bytes
+ Fun 31257172 bytes
+ Unsafe 4384 bytes
+ Unrated 10913415 bytes
+
+-----------------------------------------------------------
+* NOTE: This is demo app to show *some* nDPI features.
+* In this demo we have implemented only some basic features
+* just to show you what you can do with the library. Feel
+* free to extend it and send us the patches for inclusion
+------------------------------------------------------------
+
+Using nDPI (1.8.0-dev-707-6a27b62) [1 thread(s)]
+Reading packets from pcap file test.pcap...
+Running thread 0...
+
+nDPI Memory statistics:
+ nDPI Memory (once): 110.55 KB
+ Flow Memory (per flow): 1.95 KB
+ Actual Memory: 3.46 MB
+ Peak Memory: 3.46 MB
+
+Traffic statistics:
+ Ethernet bytes: 75948198 (includes ethernet CRC/IFC/trailer)
+ Discarded bytes: 55256
+ IP packets: 60265 of 61155 packets total
+ IP bytes: 74501838 (avg pkt size 1218 bytes)
+ Unique flows: 545
+ TCP Packets: 21188
+ UDP Packets: 39042
+ VLAN Packets: 0
+ MPLS Packets: 0
+ PPPoE Packets: 0
+ Fragmented Packets: 4
+ Max Packet size: 64260
+ Packet Len < 64: 30624
+ Packet Len 64-128: 1158
+ Packet Len 128-256: 674
+ Packet Len 256-1024: 817
+ Packet Len 1024-1500: 21924
+ Packet Len > 1500: 5068
+ nDPI throughput: 1.32 M pps / 12.42 Gb/sec
+ Traffic throughput: 228.03 pps / 2.19 Mb/sec
+ Traffic duration: 264.290 sec
+ Guessed flow protos: 9
+
+
+Detected protocols:
+ Unknown packets: 6126 bytes: 10913415 flows: 46
+ FTP_CONTROL packets: 42 bytes: 4384 flows: 1
+ DNS packets: 66 bytes: 6520 flows: 23
+ IPP packets: 46 bytes: 12059 flows: 1
+ HTTP packets: 377 bytes: 113616 flows: 24
+ MDNS packets: 43 bytes: 11742 flows: 9
+ NetBIOS packets: 48 bytes: 4754 flows: 12
+ SSDP packets: 101 bytes: 32533 flows: 21
+ DHCP packets: 21 bytes: 7346 flows: 2
+ BitTorrent packets: 37639 bytes: 29656716 flows: 65
+ ICMP packets: 15 bytes: 4956 flows: 5
+ IGMP packets: 10 bytes: 600 flows: 9
+ SSL packets: 1199 bytes: 622508 flows: 24
+ ICMPV6 packets: 2 bytes: 172 flows: 2
+ DHCPV6 packets: 1 bytes: 144 flows: 1
+ Facebook packets: 349 bytes: 206444 flows: 21
+ Twitter packets: 137 bytes: 45679 flows: 8
+ Dropbox packets: 155 bytes: 45358 flows: 12
+ GMail packets: 35 bytes: 10470 flows: 3
+ YouTube packets: 11721 bytes: 31050728 flows: 33
+ Skype packets: 237 bytes: 35082 flows: 30
+ Google packets: 558 bytes: 164639 flows: 52
+ WhatsApp packets: 969 bytes: 1477350 flows: 17
+ Viber packets: 60 bytes: 27602 flows: 1
+ LLMNR packets: 71 bytes: 5297 flows: 36
+ Amazon packets: 89 bytes: 23572 flows: 9
+ QUIC packets: 41 bytes: 3474 flows: 1
+ BJNP packets: 72 bytes: 4320 flows: 72
+ Microsoft packets: 35 bytes: 10358 flows: 5
+
+
+Protocol statistics:
+ Safe 632978 bytes
+ Acceptable 31693889 bytes
+ Fun 31257172 bytes
+ Unsafe 4384 bytes
+ Unrated 10913415 bytes
+
+-----------------------------------------------------------
+* NOTE: This is demo app to show *some* nDPI features.
+* In this demo we have implemented only some basic features
+* just to show you what you can do with the library. Feel
+* free to extend it and send us the patches for inclusion
+------------------------------------------------------------
+
+Using nDPI (1.8.0-dev-707-6a27b62) [1 thread(s)]
+Reading packets from pcap file test.pcap...
+Running thread 0...
+
+nDPI Memory statistics:
+ nDPI Memory (once): 110.55 KB
+ Flow Memory (per flow): 1.95 KB
+ Actual Memory: 3.46 MB
+ Peak Memory: 3.46 MB
+
+Traffic statistics:
+ Ethernet bytes: 75948198 (includes ethernet CRC/IFC/trailer)
+ Discarded bytes: 55256
+ IP packets: 60265 of 61155 packets total
+ IP bytes: 74501838 (avg pkt size 1218 bytes)
+ Unique flows: 545
+ TCP Packets: 21188
+ UDP Packets: 39042
+ VLAN Packets: 0
+ MPLS Packets: 0
+ PPPoE Packets: 0
+ Fragmented Packets: 4
+ Max Packet size: 64260
+ Packet Len < 64: 30624
+ Packet Len 64-128: 1158
+ Packet Len 128-256: 674
+ Packet Len 256-1024: 817
+ Packet Len 1024-1500: 21924
+ Packet Len > 1500: 5068
+ nDPI throughput: 1.54 M pps / 14.46 Gb/sec
+ Traffic throughput: 228.03 pps / 2.19 Mb/sec
+ Traffic duration: 264.290 sec
+ Guessed flow protos: 9
+
+
+Detected protocols:
+ Unknown packets: 6126 bytes: 10913415 flows: 46
+ FTP_CONTROL packets: 42 bytes: 4384 flows: 1
+ DNS packets: 66 bytes: 6520 flows: 23
+ IPP packets: 46 bytes: 12059 flows: 1
+ HTTP packets: 377 bytes: 113616 flows: 24
+ MDNS packets: 43 bytes: 11742 flows: 9
+ NetBIOS packets: 48 bytes: 4754 flows: 12
+ SSDP packets: 101 bytes: 32533 flows: 21
+ DHCP packets: 21 bytes: 7346 flows: 2
+ BitTorrent packets: 37639 bytes: 29656716 flows: 65
+ ICMP packets: 15 bytes: 4956 flows: 5
+ IGMP packets: 10 bytes: 600 flows: 9
+ SSL packets: 1199 bytes: 622508 flows: 24
+ ICMPV6 packets: 2 bytes: 172 flows: 2
+ DHCPV6 packets: 1 bytes: 144 flows: 1
+ Facebook packets: 349 bytes: 206444 flows: 21
+ Twitter packets: 137 bytes: 45679 flows: 8
+ Dropbox packets: 155 bytes: 45358 flows: 12
+ GMail packets: 35 bytes: 10470 flows: 3
+ YouTube packets: 11721 bytes: 31050728 flows: 33
+ Skype packets: 237 bytes: 35082 flows: 30
+ Google packets: 558 bytes: 164639 flows: 52
+ WhatsApp packets: 969 bytes: 1477350 flows: 17
+ Viber packets: 60 bytes: 27602 flows: 1
+ LLMNR packets: 71 bytes: 5297 flows: 36
+ Amazon packets: 89 bytes: 23572 flows: 9
+ QUIC packets: 41 bytes: 3474 flows: 1
+ BJNP packets: 72 bytes: 4320 flows: 72
+ Microsoft packets: 35 bytes: 10358 flows: 5
+
+
+Protocol statistics:
+ Safe 632978 bytes
+ Acceptable 31693889 bytes
+ Fun 31257172 bytes
+ Unsafe 4384 bytes
+ Unrated 10913415 bytes
+
+-----------------------------------------------------------
+* NOTE: This is demo app to show *some* nDPI features.
+* In this demo we have implemented only some basic features
+* just to show you what you can do with the library. Feel
+* free to extend it and send us the patches for inclusion
+------------------------------------------------------------
+
+Using nDPI (1.8.0-dev-707-6a27b62) [1 thread(s)]
+Reading packets from pcap file test.pcap...
+Running thread 0...
+
+nDPI Memory statistics:
+ nDPI Memory (once): 110.55 KB
+ Flow Memory (per flow): 1.95 KB
+ Actual Memory: 3.46 MB
+ Peak Memory: 3.46 MB
+
+Traffic statistics:
+ Ethernet bytes: 75948198 (includes ethernet CRC/IFC/trailer)
+ Discarded bytes: 55256
+ IP packets: 60265 of 61155 packets total
+ IP bytes: 74501838 (avg pkt size 1218 bytes)
+ Unique flows: 545
+ TCP Packets: 21188
+ UDP Packets: 39042
+ VLAN Packets: 0
+ MPLS Packets: 0
+ PPPoE Packets: 0
+ Fragmented Packets: 4
+ Max Packet size: 64260
+ Packet Len < 64: 30624
+ Packet Len 64-128: 1158
+ Packet Len 128-256: 674
+ Packet Len 256-1024: 817
+ Packet Len 1024-1500: 21924
+ Packet Len > 1500: 5068
+ nDPI throughput: 1.54 M pps / 14.49 Gb/sec
+ Traffic throughput: 228.03 pps / 2.19 Mb/sec
+ Traffic duration: 264.290 sec
+ Guessed flow protos: 9
+
+
+Detected protocols:
+ Unknown packets: 6126 bytes: 10913415 flows: 46
+ FTP_CONTROL packets: 42 bytes: 4384 flows: 1
+ DNS packets: 66 bytes: 6520 flows: 23
+ IPP packets: 46 bytes: 12059 flows: 1
+ HTTP packets: 377 bytes: 113616 flows: 24
+ MDNS packets: 43 bytes: 11742 flows: 9
+ NetBIOS packets: 48 bytes: 4754 flows: 12
+ SSDP packets: 101 bytes: 32533 flows: 21
+ DHCP packets: 21 bytes: 7346 flows: 2
+ BitTorrent packets: 37639 bytes: 29656716 flows: 65
+ ICMP packets: 15 bytes: 4956 flows: 5
+ IGMP packets: 10 bytes: 600 flows: 9
+ SSL packets: 1199 bytes: 622508 flows: 24
+ ICMPV6 packets: 2 bytes: 172 flows: 2
+ DHCPV6 packets: 1 bytes: 144 flows: 1
+ Facebook packets: 349 bytes: 206444 flows: 21
+ Twitter packets: 137 bytes: 45679 flows: 8
+ Dropbox packets: 155 bytes: 45358 flows: 12
+ GMail packets: 35 bytes: 10470 flows: 3
+ YouTube packets: 11721 bytes: 31050728 flows: 33
+ Skype packets: 237 bytes: 35082 flows: 30
+ Google packets: 558 bytes: 164639 flows: 52
+ WhatsApp packets: 969 bytes: 1477350 flows: 17
+ Viber packets: 60 bytes: 27602 flows: 1
+ LLMNR packets: 71 bytes: 5297 flows: 36
+ Amazon packets: 89 bytes: 23572 flows: 9
+ QUIC packets: 41 bytes: 3474 flows: 1
+ BJNP packets: 72 bytes: 4320 flows: 72
+ Microsoft packets: 35 bytes: 10358 flows: 5
+
+
+Protocol statistics:
+ Safe 632978 bytes
+ Acceptable 31693889 bytes
+ Fun 31257172 bytes
+ Unsafe 4384 bytes
+ Unrated 10913415 bytes
+
+-----------------------------------------------------------
+* NOTE: This is demo app to show *some* nDPI features.
+* In this demo we have implemented only some basic features
+* just to show you what you can do with the library. Feel
+* free to extend it and send us the patches for inclusion
+------------------------------------------------------------
+
+Using nDPI (1.8.0-dev-707-6a27b62) [1 thread(s)]
+Reading packets from pcap file test.pcap...
+Running thread 0...
+
+nDPI Memory statistics:
+ nDPI Memory (once): 110.55 KB
+ Flow Memory (per flow): 1.95 KB
+ Actual Memory: 3.46 MB
+ Peak Memory: 3.46 MB
+
+Traffic statistics:
+ Ethernet bytes: 75948198 (includes ethernet CRC/IFC/trailer)
+ Discarded bytes: 55256
+ IP packets: 60265 of 61155 packets total
+ IP bytes: 74501838 (avg pkt size 1218 bytes)
+ Unique flows: 545
+ TCP Packets: 21188
+ UDP Packets: 39042
+ VLAN Packets: 0
+ MPLS Packets: 0
+ PPPoE Packets: 0
+ Fragmented Packets: 4
+ Max Packet size: 64260
+ Packet Len < 64: 30624
+ Packet Len 64-128: 1158
+ Packet Len 128-256: 674
+ Packet Len 256-1024: 817
+ Packet Len 1024-1500: 21924
+ Packet Len > 1500: 5068
+ nDPI throughput: 1.37 M pps / 12.89 Gb/sec
+ Traffic throughput: 228.03 pps / 2.19 Mb/sec
+ Traffic duration: 264.290 sec
+ Guessed flow protos: 9
+
+
+Detected protocols:
+ Unknown packets: 6126 bytes: 10913415 flows: 46
+ FTP_CONTROL packets: 42 bytes: 4384 flows: 1
+ DNS packets: 66 bytes: 6520 flows: 23
+ IPP packets: 46 bytes: 12059 flows: 1
+ HTTP packets: 377 bytes: 113616 flows: 24
+ MDNS packets: 43 bytes: 11742 flows: 9
+ NetBIOS packets: 48 bytes: 4754 flows: 12
+ SSDP packets: 101 bytes: 32533 flows: 21
+ DHCP packets: 21 bytes: 7346 flows: 2
+ BitTorrent packets: 37639 bytes: 29656716 flows: 65
+ ICMP packets: 15 bytes: 4956 flows: 5
+ IGMP packets: 10 bytes: 600 flows: 9
+ SSL packets: 1199 bytes: 622508 flows: 24
+ ICMPV6 packets: 2 bytes: 172 flows: 2
+ DHCPV6 packets: 1 bytes: 144 flows: 1
+ Facebook packets: 349 bytes: 206444 flows: 21
+ Twitter packets: 137 bytes: 45679 flows: 8
+ Dropbox packets: 155 bytes: 45358 flows: 12
+ GMail packets: 35 bytes: 10470 flows: 3
+ YouTube packets: 11721 bytes: 31050728 flows: 33
+ Skype packets: 237 bytes: 35082 flows: 30
+ Google packets: 558 bytes: 164639 flows: 52
+ WhatsApp packets: 969 bytes: 1477350 flows: 17
+ Viber packets: 60 bytes: 27602 flows: 1
+ LLMNR packets: 71 bytes: 5297 flows: 36
+ Amazon packets: 89 bytes: 23572 flows: 9
+ QUIC packets: 41 bytes: 3474 flows: 1
+ BJNP packets: 72 bytes: 4320 flows: 72
+ Microsoft packets: 35 bytes: 10358 flows: 5
+
+
+Protocol statistics:
+ Safe 632978 bytes
+ Acceptable 31693889 bytes
+ Fun 31257172 bytes
+ Unsafe 4384 bytes
+ Unrated 10913415 bytes
+
+-----------------------------------------------------------
+* NOTE: This is demo app to show *some* nDPI features.
+* In this demo we have implemented only some basic features
+* just to show you what you can do with the library. Feel
+* free to extend it and send us the patches for inclusion
+------------------------------------------------------------
+
+Using nDPI (1.8.0-dev-707-6a27b62) [1 thread(s)]
+Reading packets from pcap file test.pcap...
+Running thread 0...
+
+nDPI Memory statistics:
+ nDPI Memory (once): 110.55 KB
+ Flow Memory (per flow): 1.95 KB
+ Actual Memory: 3.46 MB
+ Peak Memory: 3.46 MB
+
+Traffic statistics:
+ Ethernet bytes: 75948198 (includes ethernet CRC/IFC/trailer)
+ Discarded bytes: 55256
+ IP packets: 60265 of 61155 packets total
+ IP bytes: 74501838 (avg pkt size 1218 bytes)
+ Unique flows: 545
+ TCP Packets: 21188
+ UDP Packets: 39042
+ VLAN Packets: 0
+ MPLS Packets: 0
+ PPPoE Packets: 0
+ Fragmented Packets: 4
+ Max Packet size: 64260
+ Packet Len < 64: 30624
+ Packet Len 64-128: 1158
+ Packet Len 128-256: 674
+ Packet Len 256-1024: 817
+ Packet Len 1024-1500: 21924
+ Packet Len > 1500: 5068
+ nDPI throughput: 1.55 M pps / 14.57 Gb/sec
+ Traffic throughput: 228.03 pps / 2.19 Mb/sec
+ Traffic duration: 264.290 sec
+ Guessed flow protos: 9
+
+
+Detected protocols:
+ Unknown packets: 6126 bytes: 10913415 flows: 46
+ FTP_CONTROL packets: 42 bytes: 4384 flows: 1
+ DNS packets: 66 bytes: 6520 flows: 23
+ IPP packets: 46 bytes: 12059 flows: 1
+ HTTP packets: 377 bytes: 113616 flows: 24
+ MDNS packets: 43 bytes: 11742 flows: 9
+ NetBIOS packets: 48 bytes: 4754 flows: 12
+ SSDP packets: 101 bytes: 32533 flows: 21
+ DHCP packets: 21 bytes: 7346 flows: 2
+ BitTorrent packets: 37639 bytes: 29656716 flows: 65
+ ICMP packets: 15 bytes: 4956 flows: 5
+ IGMP packets: 10 bytes: 600 flows: 9
+ SSL packets: 1199 bytes: 622508 flows: 24
+ ICMPV6 packets: 2 bytes: 172 flows: 2
+ DHCPV6 packets: 1 bytes: 144 flows: 1
+ Facebook packets: 349 bytes: 206444 flows: 21
+ Twitter packets: 137 bytes: 45679 flows: 8
+ Dropbox packets: 155 bytes: 45358 flows: 12
+ GMail packets: 35 bytes: 10470 flows: 3
+ YouTube packets: 11721 bytes: 31050728 flows: 33
+ Skype packets: 237 bytes: 35082 flows: 30
+ Google packets: 558 bytes: 164639 flows: 52
+ WhatsApp packets: 969 bytes: 1477350 flows: 17
+ Viber packets: 60 bytes: 27602 flows: 1
+ LLMNR packets: 71 bytes: 5297 flows: 36
+ Amazon packets: 89 bytes: 23572 flows: 9
+ QUIC packets: 41 bytes: 3474 flows: 1
+ BJNP packets: 72 bytes: 4320 flows: 72
+ Microsoft packets: 35 bytes: 10358 flows: 5
+
+
+Protocol statistics:
+ Safe 632978 bytes
+ Acceptable 31693889 bytes
+ Fun 31257172 bytes
+ Unsafe 4384 bytes
+ Unrated 10913415 bytes \ No newline at end of file
diff --git a/tests/data/external/ramspeed/Floatmem b/tests/data/external/ramspeed/Floatmem
new file mode 100644
index 00000000..f3cc1e6d
--- /dev/null
+++ b/tests/data/external/ramspeed/Floatmem
@@ -0,0 +1,52 @@
+RAMspeed/SMP (Linux) v3.5.0 by Rhett M. Hollander and Paul V. Bolotoff, 2002-09
+
+8Gb per pass mode, 1 processes
+
+5-benchmark FLOATmem BatchRun mode
+
+Benchmark #1:
+FL-POINT Copy: 8220.47 MB/s
+FL-POINT Scale: 8195.78 MB/s
+FL-POINT Add: 10319.18 MB/s
+FL-POINT Triad: 10403.87 MB/s
+---
+FL-POINT AVERAGE: 9284.83 MB/s
+
+Benchmark #2:
+FL-POINT Copy: 8086.66 MB/s
+FL-POINT Scale: 7842.82 MB/s
+FL-POINT Add: 9900.13 MB/s
+FL-POINT Triad: 10029.43 MB/s
+---
+FL-POINT AVERAGE: 8964.76 MB/s
+
+Benchmark #3:
+FL-POINT Copy: 7766.98 MB/s
+FL-POINT Scale: 7837.62 MB/s
+FL-POINT Add: 9827.57 MB/s
+FL-POINT Triad: 9918.89 MB/s
+---
+FL-POINT AVERAGE: 8837.77 MB/s
+
+Benchmark #4:
+FL-POINT Copy: 7647.89 MB/s
+FL-POINT Scale: 7594.00 MB/s
+FL-POINT Add: 9873.93 MB/s
+FL-POINT Triad: 9970.89 MB/s
+---
+FL-POINT AVERAGE: 8771.68 MB/s
+
+Benchmark #5:
+FL-POINT Copy: 7821.21 MB/s
+FL-POINT Scale: 7880.56 MB/s
+FL-POINT Add: 9914.84 MB/s
+FL-POINT Triad: 10044.05 MB/s
+---
+FL-POINT AVERAGE: 8915.17 MB/s
+
+FL-POINT BatchRun Copy: 7908.64 MB/s
+FL-POINT BatchRun Scale: 7870.16 MB/s
+FL-POINT BatchRun Add: 9967.13 MB/s
+FL-POINT BatchRun Triad: 10073.43 MB/s
+---
+FL-POINT BatchRun AVERAGE: 8954.84 MB/s \ No newline at end of file
diff --git a/tests/data/external/ramspeed/Intmem b/tests/data/external/ramspeed/Intmem
new file mode 100644
index 00000000..08fffe47
--- /dev/null
+++ b/tests/data/external/ramspeed/Intmem
@@ -0,0 +1,52 @@
+RAMspeed/SMP (Linux) v3.5.0 by Rhett M. Hollander and Paul V. Bolotoff, 2002-09
+
+8Gb per pass mode, 1 processes
+
+5-benchmark INTmem BatchRun mode
+
+Benchmark #1:
+INTEGER Copy: 11493.80 MB/s
+INTEGER Scale: 11527.61 MB/s
+INTEGER Add: 11567.60 MB/s
+INTEGER Triad: 11546.06 MB/s
+---
+INTEGER AVERAGE: 11533.77 MB/s
+
+Benchmark #2:
+INTEGER Copy: 11580.06 MB/s
+INTEGER Scale: 11617.25 MB/s
+INTEGER Add: 11748.95 MB/s
+INTEGER Triad: 11837.43 MB/s
+---
+INTEGER AVERAGE: 11695.92 MB/s
+
+Benchmark #3:
+INTEGER Copy: 11674.45 MB/s
+INTEGER Scale: 11566.59 MB/s
+INTEGER Add: 11643.59 MB/s
+INTEGER Triad: 11633.42 MB/s
+---
+INTEGER AVERAGE: 11629.51 MB/s
+
+Benchmark #4:
+INTEGER Copy: 11496.38 MB/s
+INTEGER Scale: 11528.06 MB/s
+INTEGER Add: 11641.10 MB/s
+INTEGER Triad: 11742.61 MB/s
+---
+INTEGER AVERAGE: 11602.04 MB/s
+
+Benchmark #5:
+INTEGER Copy: 11568.45 MB/s
+INTEGER Scale: 11579.32 MB/s
+INTEGER Add: 11646.55 MB/s
+INTEGER Triad: 11596.57 MB/s
+---
+INTEGER AVERAGE: 11597.72 MB/s
+
+INTEGER BatchRun Copy: 11562.63 MB/s
+INTEGER BatchRun Scale: 11563.77 MB/s
+INTEGER BatchRun Add: 11649.55 MB/s
+INTEGER BatchRun Triad: 11671.22 MB/s
+---
+INTEGER BatchRun AVERAGE: 11611.79 MB/s \ No newline at end of file
diff --git a/tests/data/external/ssl/AES-128-CBC_dump b/tests/data/external/ssl/AES-128-CBC_dump
new file mode 100644
index 00000000..32568e14
--- /dev/null
+++ b/tests/data/external/ssl/AES-128-CBC_dump
@@ -0,0 +1,7 @@
+OpenSSL 1.0.2f 28 Jan 2016
+built on: reproducible build, date unspecified
+options:bn(64,64) rc4(16x,int) des(idx,cisc,16,int) aes(partial) idea(int) blowfish(idx)
+compiler: gcc -I. -I.. -I../include -DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -Wa,--noexecstack -m64 -DL_ENDIAN -O3 -Wall -DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DMD5_ASM -DAES_ASM -DVPAES_ASM -DBSAES_ASM -DWHIRLPOOL_ASM -DGHASH_ASM -DECP_NISTZ256_ASM
+The 'numbers' are in 1000s of bytes per second processed.
+type 16 bytes 64 bytes 256 bytes 1024 bytes 8192 bytes
+aes-128-cbc 533103.05k 570042.22k 580021.25k 584568.83k 599470.83k \ No newline at end of file
diff --git a/tests/data/external/ssl/RSA_dump b/tests/data/external/ssl/RSA_dump
new file mode 100644
index 00000000..55e40792
--- /dev/null
+++ b/tests/data/external/ssl/RSA_dump
@@ -0,0 +1,9 @@
+OpenSSL 1.0.2f 28 Jan 2016
+built on: reproducible build, date unspecified
+options:bn(64,64) rc4(16x,int) des(idx,cisc,16,int) aes(partial) idea(int) blowfish(idx)
+compiler: gcc -I. -I.. -I../include -DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -Wa,--noexecstack -m64 -DL_ENDIAN -O3 -Wall -DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DMD5_ASM -DAES_ASM -DVPAES_ASM -DBSAES_ASM -DWHIRLPOOL_ASM -DGHASH_ASM -DECP_NISTZ256_ASM
+ sign verify sign/s verify/s
+rsa 512 bits 0.000056s 0.000004s 17828.4 222903.5
+rsa 1024 bits 0.000169s 0.000011s 5923.9 88397.9
+rsa 2048 bits 0.000793s 0.000037s 1261.4 26951.3
+rsa 4096 bits 0.008280s 0.000131s 120.8 7633.7
diff --git a/tests/unit/api/conftest.py b/tests/unit/api/conftest.py
new file mode 100644
index 00000000..23a3be82
--- /dev/null
+++ b/tests/unit/api/conftest.py
@@ -0,0 +1,22 @@
+##############################################################################
+# 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 pytest
+
+from qtip.api import __main__
+
+
+@pytest.fixture(scope="session")
+def app():
+ return __main__.get_app().app
+
+
+@pytest.fixture(scope="session")
+def app_client(app):
+ return app.test_client()
diff --git a/tests/unit/api/metric_controller_test.py b/tests/unit/api/metric_controller_test.py
new file mode 100644
index 00000000..caba7972
--- /dev/null
+++ b/tests/unit/api/metric_controller_test.py
@@ -0,0 +1,37 @@
+##############################################################################
+# 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 httplib
+import json
+
+from qtip.base.constant import BaseProp
+
+
+def test_get_list_metrics(app_client):
+ response_success = app_client.get("/v1.0/metrics")
+ assert response_success.status_code == httplib.OK
+ metric_list = json.loads(response_success.data)['metrics']
+ assert len(metric_list) > 0
+ assert metric_list[0].endswith('.yaml')
+
+
+def test_get_metric(app_client):
+ response_success = app_client.get("/v1.0/metrics/dpi.yaml")
+ assert response_success.status_code == httplib.OK
+ metric_data = json.loads(response_success.data)
+ assert BaseProp.NAME in metric_data
+ assert BaseProp.WORKLOADS in metric_data
+ assert isinstance(metric_data[BaseProp.WORKLOADS], list)
+
+
+def test_get_metric_not_found(app_client):
+ response_not_found = app_client.get("/v1.0/metrics/fake.yaml")
+ response_data = json.loads(response_not_found.data)
+ assert response_not_found.status_code == httplib.NOT_FOUND
+ assert response_data['title'] == "Metric not found"
diff --git a/tests/unit/api/plan_controller_test.py b/tests/unit/api/plan_controller_test.py
new file mode 100644
index 00000000..136bd3c6
--- /dev/null
+++ b/tests/unit/api/plan_controller_test.py
@@ -0,0 +1,49 @@
+##############################################################################
+# 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 httplib
+import json
+
+
+from qtip.loader.plan import PlanProp
+
+
+def test_invalid_url(app_client):
+ response_url_not_found = app_client.get("/v1.0/fakeresource")
+ assert response_url_not_found.status_code == httplib.NOT_FOUND
+
+
+def test_get_list_plans(app_client):
+ response_success = app_client.get("/v1.0/plans")
+ assert response_success.status_code == httplib.OK
+ plan_list = json.loads(response_success.data)['plans']
+ assert len(plan_list) > 0
+ assert plan_list[0].endswith('.yaml')
+
+
+def test_get_plan(app_client):
+ response_success = app_client.get("/v1.0/plans/sample.yaml")
+ assert response_success.status_code == httplib.OK
+ plan_data = json.loads(response_success.data)
+ assert PlanProp.NAME in plan_data
+ assert PlanProp.DESCRIPTION in plan_data
+ assert PlanProp.CONFIG in plan_data
+ assert PlanProp.QPIS in plan_data
+
+
+def test_get_plan_not_found(app_client):
+ response_not_found = app_client.get("/v1.0/plans/fake.yaml")
+ response_data = json.loads(response_not_found.data)
+ assert response_not_found.status_code == httplib.NOT_FOUND
+ assert response_data['title'] == "Plan not found"
+
+
+def test_runner_not_implemented(app_client):
+ response_error = app_client.post("/v1.0/plans/fake.yaml?action=run", follow_redirects=False)
+ assert response_error.status_code == httplib.NOT_IMPLEMENTED
diff --git a/tests/unit/api/qpi_controller_test.py b/tests/unit/api/qpi_controller_test.py
new file mode 100644
index 00000000..6291dd9b
--- /dev/null
+++ b/tests/unit/api/qpi_controller_test.py
@@ -0,0 +1,43 @@
+##############################################################################
+# 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 httplib
+import json
+
+from qtip.base.constant import FormulaName
+from qtip.base.constant import SpecProp
+
+
+def test_get_list_qpis(app_client):
+ response_success = app_client.get("/v1.0/qpis")
+ assert response_success.status_code == httplib.OK
+ qpi_spec_list = json.loads(response_success.data)['qpis']
+ assert len(qpi_spec_list) > 0
+ assert qpi_spec_list[0].endswith('.yaml')
+
+
+def test_get_qpi(app_client):
+ response_success = app_client.get("/v1.0/qpis/compute.yaml")
+ assert response_success.status_code == httplib.OK
+ qpi_data = json.loads(response_success.data)
+ assert SpecProp.DESCRIPTION in qpi_data
+ assert SpecProp.FORMULA in qpi_data
+ assert SpecProp.SECTIONS in qpi_data
+ assert qpi_data[SpecProp.FORMULA] in FormulaName.__dict__.values()
+ sections = qpi_data[SpecProp.SECTIONS]
+ assert isinstance(sections, list)
+ for section in sections:
+ assert SpecProp.NAME in section
+
+
+def test_get_qpi_not_found(app_client):
+ response_not_found = app_client.get("/v1.0/qpis/fake.yaml")
+ response_data = json.loads(response_not_found.data)
+ assert response_not_found.status_code == httplib.NOT_FOUND
+ assert response_data['title'] == "QPI not found"
diff --git a/tests/unit/cli/cmd_metric_test.py b/tests/unit/cli/cmd_metric_test.py
index 30f3448a..cd496ad9 100644
--- a/tests/unit/cli/cmd_metric_test.py
+++ b/tests/unit/cli/cmd_metric_test.py
@@ -1,5 +1,5 @@
###############################################################
-# Copyright (c) 2016 ZTE Corp and others.
+# Copyright (c) 2017 taseer94@gmail.com and others.
#
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Apache License, Version 2.0
@@ -8,8 +8,8 @@
##############################################################################
import pytest
-from click.testing import CliRunner
+from click.testing import CliRunner
from qtip.cli.entry import cli
@@ -20,7 +20,9 @@ def runner():
def test_list(runner):
result = runner.invoke(cli, ['metric', 'list'])
- assert result.output == ''
+ assert 'dhrystone' and 'whetstone' and 'dpi' and \
+ 'ramspeed' and 'fake-metric' and 'ssl' \
+ in result.output
def test_run(runner):
@@ -32,8 +34,10 @@ def test_run(runner):
def test_show(runner):
- result = runner.invoke(cli, ['metric', 'show', 'fake-metric'])
- assert result.output == ''
+ result = runner.invoke(cli, ['metric', 'show', 'dhrystone'])
+ assert 'Name: dhrystone' in result.output
+ assert 'Description: A synthetic computing benchmark program intended to be representative of' \
+ 'system (integer) programming.'
result = runner.invoke(cli, ['metric', 'show'])
assert 'Missing argument "name".' in result.output
diff --git a/tests/unit/cli/cmd_plan_test.py b/tests/unit/cli/cmd_plan_test.py
index 1708c340..30025ae0 100644
--- a/tests/unit/cli/cmd_plan_test.py
+++ b/tests/unit/cli/cmd_plan_test.py
@@ -1,5 +1,5 @@
###############################################################
-# Copyright (c) 2016 ZTE Corp and others.
+# Copyright (c) 2017 taseer94@gmail.com and others.
#
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Apache License, Version 2.0
@@ -20,7 +20,7 @@ def runner():
def test_list(runner):
result = runner.invoke(cli, ['plan', 'list'])
- assert result.output == ''
+ assert 'Plan' and 'compute' and 'sample' in result.output
def test_run(runner):
@@ -32,8 +32,9 @@ def test_run(runner):
def test_show(runner):
- result = runner.invoke(cli, ['plan', 'show', 'fake-plan'])
- assert result.output == ''
+ result = runner.invoke(cli, ['plan', 'show', 'compute'])
+ assert 'Name: compute QPI' in result.output
+ assert 'Description: compute QPI profile'
result = runner.invoke(cli, ['plan', 'show'])
assert 'Missing argument "name".' in result.output
diff --git a/tests/unit/cli/cmd_qpi_test.py b/tests/unit/cli/cmd_qpi_test.py
index 485d5462..3d2c2613 100644
--- a/tests/unit/cli/cmd_qpi_test.py
+++ b/tests/unit/cli/cmd_qpi_test.py
@@ -1,5 +1,5 @@
###############################################################
-# Copyright (c) 2016 ZTE Corp and others.
+# Copyright (c) 2017 taseer94@gmail.com and others.
#
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Apache License, Version 2.0
@@ -8,9 +8,9 @@
##############################################################################
import pytest
-from click.testing import CliRunner
from qtip.cli.entry import cli
+from click.testing import CliRunner
@pytest.fixture(scope="module")
@@ -20,7 +20,7 @@ def runner():
def test_list(runner):
result = runner.invoke(cli, ['qpi', 'list'])
- assert result.output == ''
+ assert 'QPIs' and 'compute' in result.output
def test_run(runner):
@@ -32,8 +32,9 @@ def test_run(runner):
def test_show(runner):
- result = runner.invoke(cli, ['qpi', 'show', 'fake-qpi'])
- assert result.output == ''
+ result = runner.invoke(cli, ['qpi', 'show', 'compute'])
+ assert 'Name: compute' in result.output
+ assert 'Description: sample performance index of computing' in result.output
result = runner.invoke(cli, ['qpi', 'show'])
assert 'Missing argument "name".' in result.output
diff --git a/tests/unit/cli/cmd_report_test.py b/tests/unit/cli/cmd_report_test.py
new file mode 100644
index 00000000..963ce987
--- /dev/null
+++ b/tests/unit/cli/cmd_report_test.py
@@ -0,0 +1,91 @@
+###############################################################
+# Copyright (c) 2017 taseer94@gmail.com 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 pytest
+
+from click.testing import CliRunner
+from qtip.cli.entry import cli
+
+
+@pytest.fixture(scope="module")
+def runner():
+ return CliRunner()
+
+
+def test_dhrystone(runner):
+ """Test dhrystone report"""
+
+ result = runner.invoke(cli, ['report', 'show', 'dhrystone'])
+ assert "Benchmark: dhrystone" in result.output
+ assert "CPU Usage: 3%" in result.output
+ assert "Number: 40" in result.output
+ assert "Score: 63529.6" in result.output
+ assert "Single CPU:" in result.output
+ assert "Total CPUs: 40" in result.output
+
+
+def test_whetstone(runner):
+ """ Test whetstone output"""
+
+ result = runner.invoke(cli, ['report', 'show', 'whetstone'])
+ assert "Benchmark: whetstone" in result.output
+ assert "CPU Usage: 3%" in result.output
+ assert "Results:" in result.output
+ assert "Multi CPU:" in result.output
+ assert "Number: 40" in result.output
+ assert "Score: 21198.3" in result.output
+ assert "Single CPU:" in result.output
+
+
+def test_dpi(runner):
+ """ Test dpi report"""
+ result = runner.invoke(cli, ['report', 'show', 'dpi'])
+ assert "Benchmark: dpi" in result.output
+ assert "CPU Usage: 3%" in result.output
+ assert "Bits per Second: 3.638" in result.output
+ assert "Packets per Second: 1.45" in result.output
+ assert "Bits per Second: 3.69" in result.output
+ assert "Packets per Second: 1.458" in result.output
+
+
+def test_ramspeed(runner):
+ """ Test ramspeed report """
+ result = runner.invoke(cli, ['report', 'show', 'ramspeed'])
+ assert "Benchmark: ramspeed" in result.output
+ assert "CPU Usage: 3%" in result.output
+ assert "Float Addition: 10217.62" in result.output
+ assert "Float Average: 9176.88" in result.output
+ assert "Float Copy: 8127.13" in result.output
+ assert "Float Scale: 8085.40" in result.output
+ assert "Float Triad: 10277.38" in result.output
+ assert "Integer Addition: 11471.63" in result.output
+ assert "Integer Average: 11396.35" in result.output
+
+
+def test_ssl(runner):
+ """ Test ssl report"""
+
+ result = runner.invoke(cli, ['report', 'show', 'ssl'])
+ assert "Benchmark: ssl" in result.output
+ assert "CPU Usage: 3%" in result.output
+ assert "AES 128 CBC (bytes):" in result.output
+ assert "256: 584951.30k" in result.output
+ assert "RSA SIGN:" in result.output
+ assert "2048: 9.9" in result.output
+ assert "RSA VERIFY:" in result.output
+ assert "4096: 7688.5" in result.output
+
+
+def test_sys(runner):
+ """ Test sys_info """
+
+ result = runner.invoke(cli, ['report', 'show', 'ssl'])
+ assert "System Information:" in result.output
+ assert "Host Name: node-38.zte.com.cn" in result.output
+ assert "Memory: 4403.7/128524.1MB" in result.output
diff --git a/tests/unit/cli/options_test.py b/tests/unit/cli/options_test.py
index f9472814..9dbbe6f3 100644
--- a/tests/unit/cli/options_test.py
+++ b/tests/unit/cli/options_test.py
@@ -1,5 +1,5 @@
###############################################################
-# Copyright (c) 2016 ZTE Corp and others.
+# Copyright (c) 2017 taseer94@gmail.com and others.
#
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Apache License, Version 2.0
@@ -8,8 +8,9 @@
##############################################################################
import pytest
-from click.testing import CliRunner
+import sys
+from click.testing import CliRunner
from qtip.cli.entry import cli
@@ -28,5 +29,5 @@ class TestClass(object):
assert 'dev' in result.output
def test_debug(self, runner):
- result = runner.invoke(cli, ['-d'])
- assert '' in result.output
+ runner.invoke(cli, ['-d'])
+ assert sys.tracebacklimit == 8
diff --git a/tests/unit/collector/base_test.py b/tests/unit/collector/collector_test.py
index 17fe1af1..17fe1af1 100644
--- a/tests/unit/collector/base_test.py
+++ b/tests/unit/collector/collector_test.py
diff --git a/tests/unit/loader/plan_test.py b/tests/unit/loader/plan_test.py
index 70ae2ad5..4c92e8d5 100644
--- a/tests/unit/loader/plan_test.py
+++ b/tests/unit/loader/plan_test.py
@@ -13,15 +13,18 @@ from qtip.collector.logfile import LogfileCollector
from qtip.loader.plan import load_collector
from qtip.loader.plan import Plan
from qtip.loader.plan import PlanProp
-from qtip.loader.plan import QPISpec
-def test_init(plan):
- assert plan.name == 'doctor performance profiling'
- assert isinstance(plan.content, dict)
- for qpi in plan.qpis:
- assert isinstance(qpi, QPISpec)
+def test_construct(benchmarks_root):
+ sample = Plan('sample.yaml')
+ assert isinstance(sample, Plan)
+ # fixture can not be used in pytest.mark.parametrized
+ sample = Plan('sample.yaml', [benchmarks_root])
+ assert isinstance(sample, Plan)
+
+
+def test_invalid_construct():
with pytest.raises(TypeError) as excinfo:
Plan()
assert '__init__() takes at least 2 arguments (1 given)' \
@@ -30,7 +33,7 @@ def test_init(plan):
def test_list_all(benchmarks_root):
plan_list = list(Plan.list_all(paths=[benchmarks_root]))
- assert len(plan_list) is 2
+ assert len(plan_list) is 3
for desc in plan_list:
assert PlanProp.NAME in desc
assert PlanProp.ABSPATH in desc
diff --git a/tests/unit/reporter/console_test.py b/tests/unit/reporter/console_test.py
new file mode 100644
index 00000000..aa7f848b
--- /dev/null
+++ b/tests/unit/reporter/console_test.py
@@ -0,0 +1,89 @@
+##############################################################################
+# 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
+##############################################################################
+
+import pytest
+
+from qtip.reporter.console import ConsoleReporter
+
+
+@pytest.fixture
+def console_reporter():
+ return ConsoleReporter({})
+
+
+def test_constructor(console_reporter):
+ assert isinstance(console_reporter, ConsoleReporter)
+
+
+def test_dhrystone(console_reporter):
+ """ Test dhrystone report"""
+
+ result = console_reporter.render('dhrystone')
+ assert "Benchmark: dhrystone" in result
+ assert "Number: 40" in result
+ assert "Score: 63529.6" in result
+ assert "Single CPU:" in result
+ assert "Total CPUs: 40" in result
+
+
+def test_whetstone(console_reporter):
+ """ Test whetstone output"""
+
+ result = console_reporter.render('whetstone')
+ assert "Benchmark: whetstone" in result
+ assert "Results:" in result
+ assert "Multi CPU:" in result
+ assert "Number: 40" in result
+ assert "Score: 21198.3" in result
+ assert "Single CPU:" in result
+
+
+def test_dpi(console_reporter):
+ """ Test dpi report"""
+
+ result = console_reporter.render('dpi')
+ assert "Benchmark: dpi" in result
+ assert "Bits per Second: 3.638" in result
+ assert "Packets per Second: 1.45" in result
+ assert "Bits per Second: 3.69" in result
+ assert "Packets per Second: 1.458" in result
+
+
+def test_ramspeed(console_reporter):
+ """ Test ramspeed report """
+
+ result = console_reporter.render('ramspeed')
+ assert "Float Addition: 10217.62" in result
+ assert "Float Average: 9176.88" in result
+ assert "Float Copy: 8127.13" in result
+ assert "Float Scale: 8085.40" in result
+ assert "Float Triad: 10277.38" in result
+ assert "Integer Addition: 11471.63" in result
+ assert "Integer Average: 11396.35" in result
+
+
+def test_ssl(console_reporter):
+ """ Test ssl report"""
+
+ result = console_reporter.render('ssl')
+ assert "AES 128 CBC (bytes):" in result
+ assert "256: 584951.30k" in result
+ assert "RSA SIGN:" in result
+ assert "2048: 9.9" in result
+ assert "RSA VERIFY:" in result
+ assert "4096: 7688.5" in result
+
+
+def test_sys(console_reporter):
+ """ Test sys_info """
+
+ result = console_reporter.render('ssl')
+ assert "System Information:" in result
+ assert "Host Name: node-38.zte.com.cn" in result
+ assert "Memory: 4403.7/128524.1MB" in result
diff --git a/qtip/reporter/console/__init__.py b/tests/unit/runner/runner_test.py
index 02d63288..b7da1611 100644
--- a/qtip/reporter/console/__init__.py
+++ b/tests/unit/runner/runner_test.py
@@ -8,8 +8,9 @@
##############################################################################
-from qtip.reporter.base import BaseReporter
+from qtip.runner.base import BaseRunner
-class ConsoleReporter(BaseReporter):
- """report result to console"""
+def test_constructor():
+ runner = BaseRunner()
+ assert isinstance(runner, BaseRunner)
diff --git a/tests/unit/util/env_test.py b/tests/unit/util/env_test.py
new file mode 100644
index 00000000..793d1e4e
--- /dev/null
+++ b/tests/unit/util/env_test.py
@@ -0,0 +1,307 @@
+###############################################################
+# Copyright (c) 2017 ZTE Corporation
+#
+# 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 time
+
+import pytest
+import mock
+from collections import defaultdict
+import socket
+
+from qtip.util import env
+from qtip.util.env import AnsibleEnvSetup
+
+
+@pytest.fixture(scope='session')
+def ansible_envsetup():
+ return AnsibleEnvSetup()
+
+
+@pytest.fixture()
+def hostfile(tmpdir):
+ fake_hostfile = tmpdir.join('hosts')
+ fake_hostfile.write("[hosts]\n")
+ fake_hostfile.write("10.20.0.3")
+ return fake_hostfile
+
+
+@pytest.fixture()
+def private_key(tmpdir):
+ fake_private_key = tmpdir.join('QtipKey')
+ fake_private_key.write("fake keypair")
+ return fake_private_key
+
+
+@pytest.fixture()
+def public_key(tmpdir):
+ fake_public_key = tmpdir.join('QtipKey.pub')
+ fake_public_key.write("fake public key")
+ return fake_public_key
+
+
+def test_all_files_exist(tmpdir):
+ exist_file = tmpdir.mkdir('qtip').join('hello.txt')
+ exist_file.write("hello")
+ non_exist_file = tmpdir.strpath + '/tmp.txt'
+ assert env.all_files_exist() is False
+ assert env.all_files_exist(str(exist_file))
+ assert env.all_files_exist(non_exist_file) is False
+ assert env.all_files_exist(str(exist_file), non_exist_file) is False
+
+
+def test_clean_file(tmpdir):
+ exist_file = tmpdir.mkdir('qtip').join('hello.txt')
+ exist_file.write("hello")
+ non_exist_file = tmpdir.strpath + '/tmp.txt'
+
+ assert env.clean_file() is False
+ assert env.clean_file(str(exist_file))
+ assert env.clean_file(non_exist_file)
+
+
+def test_init(ansible_envsetup):
+ assert 'AnsibleEnvSetup' in str(type(ansible_envsetup))
+ assert ansible_envsetup.keypair == defaultdict(str)
+ assert ansible_envsetup.hostfile is None
+ assert ansible_envsetup.host_ip_list == []
+
+
+def test_setup_exception(mocker, ansible_envsetup, hostfile):
+ with mock.patch.object(AnsibleEnvSetup, 'check_hostfile', side_effect=RuntimeError()):
+ mock_os = mocker.patch('sys.exit')
+ ansible_envsetup.setup({'hostfile': str(hostfile)})
+ assert mock_os.call_count == 1
+
+
+# TODO(zhihui_wu) Need find a smart way to write this pytest
+def test_setup(mocker, ansible_envsetup):
+ mock_check_hostfile = \
+ mocker.patch.object(AnsibleEnvSetup, 'check_hostfile')
+ mock_generate_default_hostfile = \
+ mocker.patch.object(AnsibleEnvSetup, 'generate_default_hostfile')
+ mock_fetch_ip = \
+ mocker.patch.object(AnsibleEnvSetup, 'fetch_host_ip_from_hostfile')
+ mock_check_keypair = \
+ mocker.patch.object(AnsibleEnvSetup, 'check_keypair')
+ mock_generate_default_keypair = \
+ mocker.patch.object(AnsibleEnvSetup, 'generate_default_keypair')
+ mock_pass_keypair = \
+ mocker.patch.object(AnsibleEnvSetup, 'pass_keypair_to_remote')
+ mock_check_ssh = \
+ mocker.patch.object(AnsibleEnvSetup, 'check_hosts_ssh_connectivity')
+
+ ansible_envsetup.setup({'keypair': str(private_key),
+ 'hostfile': str(hostfile)})
+ mock_check_hostfile.assert_called_with(str(hostfile))
+ mock_fetch_ip.assert_called_with()
+ mock_check_keypair.assert_called_with(str(private_key))
+ mock_pass_keypair.assert_called_with()
+ mock_check_ssh.assert_called_with()
+
+ ansible_envsetup.setup({'keypair': str(private_key)})
+ mock_generate_default_hostfile.assert_called_with()
+ mock_fetch_ip.assert_called_with()
+ mock_check_keypair.assert_called_with(str(private_key))
+ mock_pass_keypair.assert_called_with()
+ mock_check_ssh.assert_called_with()
+
+ ansible_envsetup.setup({'hostfile': str(hostfile)})
+ mock_check_hostfile.assert_called_with(str(hostfile))
+ mock_fetch_ip.assert_called_with()
+ mock_generate_default_keypair.assert_called_with()
+ mock_pass_keypair.assert_called_with()
+ mock_check_ssh.assert_called_with()
+
+ ansible_envsetup.setup()
+ mock_generate_default_hostfile.assert_called_with()
+ mock_fetch_ip.assert_called_with()
+ mock_generate_default_keypair.assert_called_with()
+ mock_pass_keypair.assert_called_with()
+ mock_check_ssh.assert_called_with()
+
+
+def test_check_keypair(mocker, ansible_envsetup, private_key, public_key):
+ with mocker.patch.object(env, 'all_files_exist', return_value=True):
+ ansible_envsetup.check_keypair(str(private_key))
+ assert ansible_envsetup.keypair['private'] == str(private_key)
+ assert ansible_envsetup.keypair['public'] == str(public_key)
+
+
+def test_check_keypair_failed(mocker, ansible_envsetup):
+ mocker.patch.object(env, 'all_files_exist', return_value=False)
+ with pytest.raises(RuntimeError) as excinfo:
+ ansible_envsetup.check_keypair(str(private_key))
+ assert 'The keypairs you in the configuration file ' \
+ 'is invalid or not existed.' == str(excinfo.value)
+ assert ansible_envsetup.keypair['private'] == ''
+ assert ansible_envsetup.keypair['public'] == ''
+
+
+@pytest.mark.parametrize("file_existence, expected", [
+ (True, 0),
+ (False, 1)
+])
+def test_generate_default_keypair(mocker, ansible_envsetup, file_existence, expected):
+ mock_os = mocker.patch('os.system')
+ mocker.patch.object(env, 'all_files_exist', return_value=file_existence)
+ ansible_envsetup.generate_default_keypair()
+ assert mock_os.call_count == expected
+ assert ansible_envsetup.keypair['private'] == env.PRIVATE_KEY
+ assert ansible_envsetup.keypair['public'] == env.PUBLIC_KEY
+
+
+@pytest.mark.parametrize("ips, expected", [
+ (['10.20.0.3'], 1),
+ (['10.20.0.3', '10.20.0.4'], 2)
+])
+def test_pass_keypair_to_remote_successful(mocker, ansible_envsetup, ips, expected):
+ ansible_envsetup.host_ip_list = ips
+ mock_pass_keypair = \
+ mocker.patch.object(AnsibleEnvSetup, '_pass_keypair', return_value=True)
+ ansible_envsetup.pass_keypair_to_remote()
+ assert mock_pass_keypair.call_count == expected
+
+
+def test_pass_keypair_to_remote_failed(mocker, ansible_envsetup):
+ ansible_envsetup.host_ip_list = ['10.20.0.3']
+ mocker.patch.object(AnsibleEnvSetup, '_pass_keypair', return_value=False)
+ with pytest.raises(RuntimeError) as excinfo:
+ ansible_envsetup.pass_keypair_to_remote()
+ assert "Failed on passing keypair to remote." in str(excinfo.value)
+
+
+def test_pass_keypair(monkeypatch, mocker, ansible_envsetup):
+ monkeypatch.setattr(time, 'sleep', lambda s: None)
+ mock_os = mocker.patch('os.system')
+ ansible_envsetup._pass_keypair('10.20.0.3', str(private_key))
+ assert mock_os.call_count == 2
+
+
+def test_pass_keypair_exception(ansible_envsetup):
+ with mock.patch('os.system', side_effect=Exception()) as mock_os:
+ result = ansible_envsetup._pass_keypair('10.20.0.3', str(private_key))
+ assert result is False
+ assert mock_os.call_count == 1
+
+
+def test_check_hostfile(mocker, ansible_envsetup, hostfile):
+ ansible_envsetup.check_hostfile(str(hostfile))
+ assert ansible_envsetup.hostfile == str(hostfile)
+
+ with pytest.raises(RuntimeError) as excinfo:
+ mocker.patch.object(env, 'all_files_exist', return_value=False)
+ ansible_envsetup.check_hostfile(str(hostfile))
+ assert str(excinfo.value) == 'The hostfile {0} is invalid or not ' \
+ 'existed.'.format(str(hostfile))
+
+
+def test_default_hostfile_non_existed(mocker, ansible_envsetup):
+ with mocker.patch.object(env, 'all_files_exist', return_value=False):
+ mock_generate_hostfile_via_installer = \
+ mocker.patch.object(AnsibleEnvSetup,
+ '_generate_hostfile_via_installer')
+ ansible_envsetup.generate_default_hostfile()
+ mock_generate_hostfile_via_installer.assert_called_once_with()
+
+
+def test_default_hostfile_existed(mocker, ansible_envsetup):
+ with mocker.patch.object(env, 'all_files_exist', return_value=True):
+ mock_generate_hostfile_via_installer = \
+ mocker.patch.object(AnsibleEnvSetup,
+ '_generate_hostfile_via_installer')
+ ansible_envsetup.generate_default_hostfile()
+ mock_generate_hostfile_via_installer.assert_not_called()
+
+
+@pytest.mark.parametrize("test_input, expected", [
+ (({}, KeyError), 'INSTALLER_TYPE'),
+ (({'INSTALLER_TYPE': 'fuel'}, KeyError), 'INSTALLER_IP'),
+ (({'INSTALLER_TYPE': 'fuel_1', 'INSTALLER_IP': '10.20.0.2'}, ValueError),
+ 'fuel_1 is not supported'),
+ (({'INSTALLER_TYPE': 'fuel', 'INSTALLER_IP': ''}, ValueError),
+ 'The value of environment variable INSTALLER_IP is empty')
+])
+def test_generate_hostfile_via_installer_exception(monkeypatch, ansible_envsetup, test_input, expected):
+ if test_input[0]:
+ for key in test_input[0]:
+ monkeypatch.setenv(key, test_input[0][key])
+
+ with pytest.raises(test_input[1]) as excinfo:
+ ansible_envsetup._generate_hostfile_via_installer()
+ assert expected in str(excinfo.value)
+
+
+def test_generate_hostfile_via_installer(monkeypatch, mocker, ansible_envsetup):
+ monkeypatch.setenv('INSTALLER_TYPE', 'fuel')
+ monkeypatch.setenv('INSTALLER_IP', '10.20.0.2')
+ mock_os = mocker.patch('os.system')
+ ansible_envsetup._generate_hostfile_via_installer()
+ assert mock_os.call_count == 1
+ assert ansible_envsetup.hostfile == env.HOST_FILE
+
+
+def test_fetch_host_ip_from_hostfile(ansible_envsetup, hostfile):
+ ansible_envsetup.hostfile = str(hostfile)
+ ansible_envsetup.fetch_host_ip_from_hostfile()
+ assert ansible_envsetup.host_ip_list == ['10.20.0.3']
+
+
+def test_fetch_host_ip_from_empty_hostfile(ansible_envsetup, tmpdir):
+ empty_hostfile = tmpdir.join('empty_hostfile')
+ empty_hostfile.write("")
+ ansible_envsetup.hostfile = str(empty_hostfile)
+ with pytest.raises(ValueError) as excinfo:
+ ansible_envsetup.fetch_host_ip_from_hostfile()
+ assert str(excinfo.value) == "The hostfile doesn't include host ip addresses."
+
+
+@pytest.mark.parametrize("ips, expected", [
+ (['10.20.0.3'], 1),
+ (['10.20.0.3', '10.20.0.4'], 2)
+])
+def test_check_hosts_ssh_connectivity(mocker, ansible_envsetup, ips, expected):
+ ansible_envsetup.host_ip_list = ips
+ mock_ssh_is_ok = \
+ mocker.patch.object(AnsibleEnvSetup, '_ssh_is_ok', return_value=True)
+ ansible_envsetup.check_hosts_ssh_connectivity()
+ assert mock_ssh_is_ok.call_count == expected
+
+
+def test_check_hosts_ssh_connectivity_failed(mocker, ansible_envsetup):
+ ansible_envsetup.host_ip_list = ['10.20.0.3']
+ mocker.patch.object(AnsibleEnvSetup, '_ssh_is_ok', return_value=False)
+ with pytest.raises(RuntimeError) as excinfo:
+ ansible_envsetup.check_hosts_ssh_connectivity()
+ assert "Failed on checking hosts ssh connectivity." == str(excinfo.value)
+
+
+@pytest.mark.parametrize("stderrinfo, expected", [
+ ('', True),
+ ('sorry', False)
+])
+def test_ssh_is_ok(mocker, ansible_envsetup, private_key, stderrinfo, expected):
+ stderr = mock.MagicMock()
+ stderr.readlines.return_value = stderrinfo
+ mock_sshclient = mocker.patch('paramiko.SSHClient')
+ test_ssh_client = mock_sshclient.return_value
+ test_ssh_client.exec_command.return_value = ('', '', stderr)
+ result = ansible_envsetup._ssh_is_ok('10.20.0.3', str(private_key))
+ assert result == expected
+ test_ssh_client.connect.assert_called_once_with(
+ '10.20.0.3', key_filename=str(private_key))
+ test_ssh_client.exec_command.assert_called_with('uname')
+
+
+def test_ssh_exception(monkeypatch, mocker, ansible_envsetup):
+ monkeypatch.setattr(time, 'sleep', lambda s: None)
+ mock_sshclient = mocker.patch('paramiko.SSHClient')
+ test_ssh_client = mock_sshclient.return_value
+ test_ssh_client.exec_command.side_effect = socket.error()
+ result = ansible_envsetup._ssh_is_ok('10.20.0.3', str(private_key), attempts=1)
+ assert result is False
diff --git a/tests/unit/util/logger_test.py b/tests/unit/util/logger_test.py
index 339b2bf6..78c4c109 100644
--- a/tests/unit/util/logger_test.py
+++ b/tests/unit/util/logger_test.py
@@ -1,3 +1,12 @@
+##############################################################################
+# 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
+##############################################################################
+
import pytest
from qtip.util import logger
diff --git a/third-party/License/.gitrepo b/third-party/License/.gitrepo
index 29cd5a75..03fab6f7 100644
--- a/third-party/License/.gitrepo
+++ b/third-party/License/.gitrepo
@@ -5,7 +5,7 @@
;
[subrepo]
remote = git@github.com:openzero-zte/License.git
- branch = master
- commit = 61489dae4453b66887d0d90a2244610a30f7e53c
- parent = 3e443dff14a2be02b914e66f27b549d0ed4cc600
+ branch = develop
+ commit = 88b1440008b6acac8ad65afc93606cddef63cea9
+ parent = 473deae9a10162f000c49ca49b4e31b28c4bf0d8
cmdver = 0.3.0
diff --git a/third-party/License/README.md b/third-party/License/README.md
index 0232de7e..57444c1f 100644
--- a/third-party/License/README.md
+++ b/third-party/License/README.md
@@ -5,6 +5,7 @@ A script for checking and adding license header according to [OPNFV contribution
## Quick Start
```
-$ cd <project-folder>
-$ curl https://raw.githubusercontent.com/Justin-chi/License/master/add_license.sh |bash
+$ cd <project-root>
+$ curl https://raw.githubusercontent.com/openzero-team/License/develop/add_license.sh |bash
```
+