diff options
23 files changed, 383 insertions, 64 deletions
@@ -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/qtip/cli/commands/cmd_report.py b/qtip/cli/commands/cmd_report.py new file mode 100644 index 00000000..c780e847 --- /dev/null +++ b/qtip/cli/commands/cmd_report.py @@ -0,0 +1,27 @@ +############################################################################## +# 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 + +pass_context = click.make_pass_decorator(Context, ensure=False) + + +@click.group() +@pass_context +def cli(ctx): + """ View Qtip results""" + pass + + +@cli.command('show') +@pass_context +def show(ctx): + pass 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/driver/ansible/ansible.py b/qtip/driver/ansible.py index cd17625d..cd17625d 100644 --- a/qtip/driver/ansible/ansible.py +++ b/qtip/driver/ansible.py diff --git a/qtip/driver/ansible/__init__.py b/qtip/driver/ansible/__init__.py deleted file mode 100644 index e69de29b..00000000 --- a/qtip/driver/ansible/__init__.py +++ /dev/null diff --git a/qtip/driver/ansible/playbook/bwn_ng.yaml b/qtip/driver/playbook/bwn_ng.yaml index 99477856..99477856 100644 --- a/qtip/driver/ansible/playbook/bwn_ng.yaml +++ b/qtip/driver/playbook/bwn_ng.yaml diff --git a/qtip/driver/playbook/dhrystone/clean.yaml b/qtip/driver/playbook/dhrystone/clean.yaml new file mode 100644 index 00000000..72bfab7e --- /dev/null +++ b/qtip/driver/playbook/dhrystone/clean.yaml @@ -0,0 +1,27 @@ +############################################################################## +# 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: Checking home directory + shell: echo $HOME + register: home_dir + + - name: Cleaning tempT + file: + path: '{{ home_dir.stdout }}/tempT' + state: absent + + - name: Cleaning qtip_result + file: + path: '{{ home_dir.stdout }}/qtip_result' + state: absent diff --git a/qtip/driver/playbook/dhrystone/run.yaml b/qtip/driver/playbook/dhrystone/run.yaml new file mode 100644 index 00000000..55de6597 --- /dev/null +++ b/qtip/driver/playbook/dhrystone/run.yaml @@ -0,0 +1,63 @@ +############################################################################## +# 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: Get current timestamp + set_fact: + timestamp: "{{ lookup('pipe', 'date +%Y-%m-%d-%H-%M') }}" + + - name: Checking home directory + shell: echo $HOME + register: home_dir + + - name: Fetch hostname + shell: hostname + register: host_name + + - name: Make UnixBench + shell: make --directory $HOME/tempT/UnixBench/ + + - name: Make some directories needed + file: + path: '{{ home_dir.stdout }}/qtip_result/{{ timestamp }}/{{ host_name.stdout }}' + state: directory + + - include: ../inxi.yaml + + - include: ../top.yaml + + - name: Run dhrystone + shell: ./Run -v dhrystone + args: + chdir: '{{ home_dir.stdout }}/tempT/UnixBench/' + + - name: Copying result to qtip result directory + shell: cp -r $HOME/tempT/UnixBench/results/* ./ + args: + chdir: '{{ home_dir.stdout }}/qtip_result/{{ timestamp }}/{{ host_name.stdout }}' + + - name: Copy top log to qtip result directory + shell: mv $HOME/qtip_result/top.log ./ + args: + chdir: '{{ home_dir.stdout }}/qtip_result/{{ timestamp }}/{{ host_name.stdout }}' + + - name: Copy inxi log to qtip result directory + shell: mv $HOME/qtip_result/inxi.log ./ + args: + chdir: '{{ home_dir.stdout }}/qtip_result/{{ timestamp }}/{{ host_name.stdout }}' + + - name: Fetch result files to local manchine + synchronize: + mode: pull + src: '{{ home_dir.stdout }}/qtip_result/' + dest: '{{ result_dir }}/dhrystone/logs/' diff --git a/qtip/driver/playbook/dhrystone/setup.yaml b/qtip/driver/playbook/dhrystone/setup.yaml new file mode 100644 index 00000000..430670c1 --- /dev/null +++ b/qtip/driver/playbook/dhrystone/setup.yaml @@ -0,0 +1,66 @@ +############################################################################## +# 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 dhrystone directory + file: + path: '{{ result_dir }}/dhrystone/logs/' + state: directory + +- hosts: hosts + become: yes + remote_user: root + + tasks: + - name: Checking home directory + shell: echo $HOME + register: home_dir + + - name: Cleaning tempT directory + file: + path: '{{ home_dir.stdout }}/tempT' + state: absent + + - name: Cleaning qtip_result directory + file: + path: '{{ home_dir.stdout }}/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: '{{ home_dir.stdout }}/tempT' diff --git a/qtip/driver/ansible/playbook/inxi.yaml b/qtip/driver/playbook/inxi.yaml index f6a0311d..f6a0311d 100644 --- a/qtip/driver/ansible/playbook/inxi.yaml +++ b/qtip/driver/playbook/inxi.yaml 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/ansible/playbook/top.yaml b/qtip/driver/playbook/top.yaml index 8de7e3d6..8de7e3d6 100644 --- a/qtip/driver/ansible/playbook/top.yaml +++ b/qtip/driver/playbook/top.yaml diff --git a/qtip/reporter/console.py b/qtip/reporter/console.py index 24c98e74..2b5130a6 100644 --- a/qtip/reporter/console.py +++ b/qtip/reporter/console.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,6 +7,9 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## +from jinja2 import Environment +from jinja2 import FileSystemLoader +from os import path from qtip.base import BaseActor @@ -16,8 +19,12 @@ class ConsoleReporter(BaseActor): """ def __init__(self, config, parent=None): super(ConsoleReporter, self).__init__(config, parent=parent) - # TODO(yujunz) remove PoC code - self._fmt = "{title}: {description}" + + # TODO (taseer) load template from config + tpl_loader = FileSystemLoader(path.join(path.dirname(__file__), 'templates')) + env = Environment(loader=tpl_loader) + self._template = env.get_template('timeline.j2') def render(self, var_dict): - return self._fmt.format(**var_dict) + out = self._template.render(var_dict) + return out diff --git a/qtip/reporter/templates/report.j2 b/qtip/reporter/templates/report.j2 new file mode 100644 index 00000000..766e6dde --- /dev/null +++ b/qtip/reporter/templates/report.j2 @@ -0,0 +1,22 @@ +{{ title }} + +Plan: {{ plan.name }} + +{{ qpi.name }}: {{ qpi.score }} +Sections: +{% for section in sections %} + {{ section.name }}: {{ section.score }} + + Formula: {{ section.formula }} + Metrics: + {% for metric in section.metrics %} + {{ metric.name }}: {{ metric.score }} + Formula: {{ metric.formula }} + Workloads: + {% for workload in workloads %} + {{ workload.name }}: {{ workload.score }} + {% endfor %} + {% endfor %} +{% endfor %} + +{{ signature }} diff --git a/qtip/reporter/templates/timeline.j2 b/qtip/reporter/templates/timeline.j2 index 9c18a996..d4c95c46 100644 --- a/qtip/reporter/templates/timeline.j2 +++ b/qtip/reporter/templates/timeline.j2 @@ -1,4 +1,4 @@ -{% title %} +{{ title }} {% for phase in phases %} {{ phase.name|upper }}{{ "TIME" }} {% for cp in phase.checkpoints %} diff --git a/qtip/scripts/generate_host_file.sh b/qtip/scripts/generate_host_file.sh index 1353cacd..ecc4d55f 100755 --- a/qtip/scripts/generate_host_file.sh +++ b/qtip/scripts/generate_host_file.sh @@ -10,15 +10,13 @@ usage(){ - echo "usage: $0 [-v] -i <installer_type> -a <installer_ip> -d <host_file>" >&2 - echo "[-v] Virtualized deployment" >&2 + echo "usage: $0 -t <installer_type> -i <installer_ipaddr> -d <dest_hostfile>" >&2 } info() { logger -s -t "generate_host_file.info" "$*" } - error() { logger -s -t "generate_host_file.error" "$*" exit 1 @@ -40,12 +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} ;; - d) host_file=${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 @@ -55,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 @@ -66,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" @@ -76,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 @@ -87,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+") @@ -109,11 +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 $host_file - touch $host_file - echo "[hosts]" >> $host_file - echo "$IPS" >> $host_file - cat $host_file + 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 d338115f..239c60c1 100755 --- a/qtip/scripts/qtip_creds.sh +++ b/qtip/scripts/qtip_creds.sh @@ -3,7 +3,7 @@ DEST_IP=$1 PRIVATE_KEY=$2 PUBLIC_KEY=$2.pub -KEYNAME=$(basename PRIVATE_KEY) +KEYNAME=$(basename $PRIVATE_KEY) echo $INSTALLER_TYPE echo $INSTALLER_IP diff --git a/tests/data/reporter/timeline.pickle b/tests/data/reporter/timeline.pickle new file mode 100644 index 00000000..5c870d93 --- /dev/null +++ b/tests/data/reporter/timeline.pickle @@ -0,0 +1,3 @@ +VTimeline\u000a\u000aMONITOR TIME\u000a\u000aT00 1\u000a\u000a\u000aINSPECTOR TIME\u000a\u000aT01 2\u000a\u000aT02 5\u000a\u000aT03 8\u000a\u000a\u000aCONTROLLER TIME\u000a\u000aT04 11\u000a\u000a\u000aNOTIFIER TIME\u000a\u000aT05 16\u000a\u000a\u000aEVALUATOR TIME\u000a\u000aT06 40\u000a\u000a\u000aTotal: 312ms +p0 +. diff --git a/tests/unit/cli/cmd_report.py b/tests/unit/cli/cmd_report.py new file mode 100644 index 00000000..e010b960 --- /dev/null +++ b/tests/unit/cli/cmd_report.py @@ -0,0 +1,23 @@ +############################################################### +# 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 +############################################################################## + +import pytest +from click.testing import CliRunner + +from qtip.cli.entry import cli + + +@pytest.fixture(scope="module") +def runner(): + return CliRunner() + + +def test_show(runner): + result = runner.invoke(cli, ['report', 'show']) + assert 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/reporter/console_test.py b/tests/unit/reporter/console_test.py index 8150239e..d2816690 100644 --- a/tests/unit/reporter/console_test.py +++ b/tests/unit/reporter/console_test.py @@ -7,7 +7,10 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## +import pickle import pytest +import os + from qtip.reporter.console import ConsoleReporter @@ -21,9 +24,16 @@ def test_constructor(console_reporter): def test_render(console_reporter): - var_dict = { - 'title': 'fake title', - 'description': 'fake description' - } - output = console_reporter.render(var_dict=var_dict) - assert output == 'fake title: fake description' + var_dict = {'title': 'Timeline', 'total': '312ms', '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'}]}]} + + result = console_reporter.render(var_dict=var_dict) + path = os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, + os.pardir, 'tests/data/reporter/') + timeline = pickle.load(open(path + 'timeline.pickle', 'rb')) + assert result == timeline 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 ``` + |