diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/generate_glusto_config/README.md | 34 | ||||
-rw-r--r-- | tools/generate_glusto_config/examples/sample_glusto_config.yaml | 20 | ||||
-rw-r--r-- | tools/generate_glusto_config/generate_glusto_config.py | 74 | ||||
-rw-r--r-- | tools/generate_glusto_config/glusto_config_template.jinja | 40 | ||||
-rw-r--r-- | tools/generate_glusto_config/setup.py | 32 | ||||
-rw-r--r-- | tools/get_sosreports/README.md | 45 | ||||
-rw-r--r-- | tools/get_sosreports/get_sosreports.py | 190 | ||||
-rw-r--r-- | tools/get_sosreports/setup.py | 33 | ||||
-rw-r--r-- | tools/log_splitter/README.md | 37 | ||||
-rw-r--r-- | tools/log_splitter/log_splitter.py | 100 | ||||
-rw-r--r-- | tools/log_splitter/setup.py | 33 | ||||
-rw-r--r-- | tools/setup_passwordless_ssh/README.md | 47 | ||||
-rw-r--r-- | tools/setup_passwordless_ssh/setup.py | 31 | ||||
-rw-r--r-- | tools/setup_passwordless_ssh/setup_passwordless_ssh.py | 147 | ||||
-rw-r--r-- | tools/verify_test_execution/README.md | 38 | ||||
-rw-r--r-- | tools/verify_test_execution/verify_test_execution.py | 157 |
16 files changed, 1058 insertions, 0 deletions
diff --git a/tools/generate_glusto_config/README.md b/tools/generate_glusto_config/README.md new file mode 100644 index 000000000..ce0455d69 --- /dev/null +++ b/tools/generate_glusto_config/README.md @@ -0,0 +1,34 @@ +# generate_glusto_config +Tool to generate config file for executing glusto tests. + +## Prerequisites +Python 3.x + +## Installation +1. Change directory to the project directory. + +``` +# cd tools/generate_glusto_config +``` + +2. Now run the installation script. + +``` +# python3 setup.py install +``` + +3. To check run: + +``` +# generate_glusto_config --help +``` + +## Usage +Pass arguments to the script as shown below: + +``` +# generate_glusto_config -c examples/sample_glusto_config.yaml -t glusto_config_template.jinja -o output_config.yml +``` + +## Licence +[GPLv3](https://github.com/gluster/glusto-tests/blob/master/LICENSE) diff --git a/tools/generate_glusto_config/examples/sample_glusto_config.yaml b/tools/generate_glusto_config/examples/sample_glusto_config.yaml new file mode 100644 index 000000000..4991b2204 --- /dev/null +++ b/tools/generate_glusto_config/examples/sample_glusto_config.yaml @@ -0,0 +1,20 @@ +# 'clients' is list of Hostnames/IP's of clients in the cluster. +clients: [client_hostname1, client_hostname2] + +# 'servers' is list of Hostnames/IP's of servers in the cluster. +# Each item in list is a dict with 'Hostname/IP' of the server as key. +# The info should contain the devices to use +# for creating bricks, brick_root i.e dirname of brick mount point. + +servers: + - server_hostname1: + devices: ["/dev/vdb", "/dev/vdc", "/dev/vdd", "/dev/vde", "/dev/vdf"] + brick_root: "/bricks" + - server_hostname2: + devices: ["/dev/vdb", "/dev/vdc", "/dev/vdd", "/dev/vde", "/dev/vdf"] + brick_root: "/bricks" + +logfile: "/var/log/glusto_tests.log" + +# Mount protocol to use in the current run +mount_type: ["glusterfs"] diff --git a/tools/generate_glusto_config/generate_glusto_config.py b/tools/generate_glusto_config/generate_glusto_config.py new file mode 100644 index 000000000..ca63b1d5a --- /dev/null +++ b/tools/generate_glusto_config/generate_glusto_config.py @@ -0,0 +1,74 @@ +# Copyright (C) 2020 Red Hat, Inc. <http://www.redhat.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY :or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +import argparse + +from glusto.core import Glusto as g + + +def handle_configs(config_list): + """Load user configuration files""" + + # load user specified configs + if config_list: + config_files = config_list.split() + g.config = g.load_configs(config_files) + return True + + return False + + +def parse_args(): + """Parse arguments with newer argparse module + (adds built-in required parm) + """ + parser = argparse.ArgumentParser( + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + description='Create output file based on template and config files') + parser.add_argument("-c", "--config", + help="Config file(s) to read.", + action="store", dest="config_list", + default=None) + parser.add_argument("-t", "--template", + help="Template file to render", + action="store", dest="template_file", + default=None) + parser.add_argument("-o", "--output", + help="Output file for rendered template", + action="store", dest="output_file", + default=None) + return parser.parse_args() + + +def main(): + """Main function""" + + args = parse_args() + + if args.config_list: + handle_configs(args.config_list) + g.show_config(g.config) + + output_file = "rendered_template.txt" + if args.output_file: + output_file = args.output_file + + if args.template_file: + g.render_template(args.template_file, g.config, output_file) + + +if __name__ == '__main__': + main() diff --git a/tools/generate_glusto_config/glusto_config_template.jinja b/tools/generate_glusto_config/glusto_config_template.jinja new file mode 100644 index 000000000..3146586d8 --- /dev/null +++ b/tools/generate_glusto_config/glusto_config_template.jinja @@ -0,0 +1,40 @@ +log_file: {{logfile}} +log_level: DEBUG +remote_user: root + +# 'servers' is list of Hostnames/IP's of servers in the cluster. +servers: &servers_list{% for server_item in servers %}{% for server, value in server_item.items() %} + - {{server}}{% endfor %}{% endfor %} + +# 'clients' is list of Hostnames/IP's of clients in the cluster. +clients:{% for client in clients %} + - {{client}}{% endfor %} + +# 'servers_info' is info about each server in the cluster. +# each server_info is a dict with 'Hostname/IP' of the server as key. +# The info should contain the host(Hostname/IP) of server, devices to use +# for creating bricks, brick_root i.e dirname of brick mount point. +# Note: Use the same Hostname/IP used in the above 'servers' section. + +servers_info:{% for server_item in servers %} + {% set outer_loop = loop %} + {% for server, value in server_item.items() %} + {{server}}: &server{{ outer_loop.index }} + host: {{server}} + devices: {{ value["devices"] }} + brick_root: {{ value["brick_root"] }}{% endfor %}{% endfor %} + +# 'clients_info' is info about each client in the cluster. +# each client_info is a dict with 'Hostname/IP' of the client as key. +# The info should contain the host(Hostname/IP) of client. + +clients_info: {% for client in clients %} + {{client}}: &client{{ loop.index }} + host: {{client}}{% endfor %} + +# This is to define what volume types and mount protocols will be run +# in this current test run. + +gluster: + running_on_volumes: [] + running_on_mounts: {{mount_type}} diff --git a/tools/generate_glusto_config/setup.py b/tools/generate_glusto_config/setup.py new file mode 100644 index 000000000..f6dcab180 --- /dev/null +++ b/tools/generate_glusto_config/setup.py @@ -0,0 +1,32 @@ +#!/usr/bin/python3 +# Copyright (C) 2020 Red Hat, Inc. <http://www.redhat.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY :or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +from setuptools import setup + +setup( + name='generate_glusto_config', + author='Red Hat, Inc.', + author_email='gluster-devel@gluster.org', + url='http://www.gluster.org', + license='GPLv3+', + description=("Tool to generate config file for executing glusto tests."), + py_modules=['generate_glusto_config'], + entry_points=""" + [console_scripts] + generate_glusto_config = generate_glusto_config:main + """ +) diff --git a/tools/get_sosreports/README.md b/tools/get_sosreports/README.md new file mode 100644 index 000000000..57176f27f --- /dev/null +++ b/tools/get_sosreports/README.md @@ -0,0 +1,45 @@ +# get_sosreports +Tool to collect sosreports from all servers and clients. + +## Prerequisites +1. Python 3.x +2. Passwordless ssh should be setup. + +## Installation +1. Change directory to the project directory. + +``` +# cd tools/get_sosreports +``` + +2. Now run the installation script. + +``` +# python3 setup.py install +``` + +3. To check run: + +``` +# get_sosreports --help +``` + +## Usage +There are 2 ways of using the tool. +1. Passing IP addresses through command line seperated by comma(,): + +``` +# get_sosreports -m machine_1,machine_2,machine_3 +``` + +2. Passing a glusto-tests config file: + +``` +# get_sosreports -f config_file +``` + +**Note**: +The default destination directory is `.` (present dir) `-d` or `--dist-dir` option. + +## Licence +[GPLv3](https://github.com/gluster/glusto-tests/blob/master/LICENSE) diff --git a/tools/get_sosreports/get_sosreports.py b/tools/get_sosreports/get_sosreports.py new file mode 100644 index 000000000..962fa6d7f --- /dev/null +++ b/tools/get_sosreports/get_sosreports.py @@ -0,0 +1,190 @@ +# Copyright (C) 2020 Red Hat, Inc. <http://www.redhat.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY :or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +# Imports needed by the script. +import argparse +import os +import sys +from yaml import safe_load + + +def read_config_file(config_file): + """ + A function to read the yaml file given to the script. + + Args: + config_file(str): A config file used to run glusto-tests. + + Return: + dict: A dictornary with all the details from config file. + """ + return safe_load(open(config_file, 'r')) + + +def remove_previous_sosreports(server): + """ + A function to remove old sosreports. + + Args: + server: hostname/IP server from which sosreport + has to be removed. + + Returns: + bool: True if successful else false. + """ + cmd = ("ssh root@{} \"rm -rf /var/tmp/sosreport-*\"" + .format(server)) + ret = os.system(cmd) + if ret: + return False + return True + + +def collect_new_sosreports(server): + """ + A function to generate sosreports. + + Args: + server: hostname/IP server from which sosreport + has to be collected. + + Returns: + bool: True if successful else false. + """ + cmd = ("ssh root@{} \"sosreport --batch --name=$HOSTNAME\"" + .format(server)) + ret = os.system(cmd) + if ret: + return False + return True + + +def copy_sosreports_to_dir(server, directory): + """ + A function to copy sosreports to local dir. + + Args: + server: hostname/IP of server for passwordless ssh + has to be configured. + directory: Directory to be used to store sosreports. + + Returns: + bool: True if successful else false. + """ + cmd = ("scp root@{}:/var/tmp/sosreport-* {}" + .format(server, directory)) + ret = os.system(cmd) + if ret: + return False + return True + + +def check_and_create_dir_if_not_present(directory): + """ + A function to check and create directory if not present. + + Args: + directory: Directory to be checked/created. + + Returns: + bool: True if successful else false. + """ + if not os.path.isdir(directory): + cmd = ("mkdir -p {}".format(directory)) + ret = os.system(cmd) + if ret: + return False + else: + print("[INFO]:The dir already exists.") + return True + + +def main(): + """ + Main function of the tool. + """ + # Setting up command line arguments. + parser = argparse.ArgumentParser( + description="Tool to collect sosreports from servers and clients." + ) + parser.add_argument("-f", + "--config_file", + type=str, + dest="config_file", + help="A glusto-tests configuration file.") + parser.add_argument("-m", "--servers", type=str, + dest="servers", + help=("A list of hostnames/ips of" + " servers seperated by comma(',').")) + parser.add_argument("-d", "--dist-dir", type=str, default=".", + dest="directory", + help=("Directory where reports are to be stored." + "(Default:.)")) + args = parser.parse_args() + + # Getting list of hostname/IP. + if args.servers: + servers = args.servers.split(',') + + # Reading the config file. + if args.config_file: + config = read_config_file(args.config_file) + servers = [] + servers += config.get('clients', []) + servers += config.get('servers', []) + + # Fetching other parameters from command line. + directory = args.directory + + # Checking and creating dir if not present. + ret = check_and_create_dir_if_not_present(directory) + if not ret: + sys.exit("[ERROR]:Unable to create dir for storing sosreports.") + + try: + for server in servers: + + # Removing old sosreports from the server. + ret = remove_previous_sosreports(server) + if not ret: + sys.exit("[ERROR]:Unable to remove old sosreports on {}!" + .format(server)) + print("[INFO]:Successfully removed old sosreports on {}." + .format(server)) + + # Collecting sosreport on the server. + ret = collect_new_sosreports(server) + if not ret: + sys.exit("[ERROR]:Unable to collect sosreport on {}!" + .format(server)) + print("[INFO]:Successfully collected sosreport on {}." + .format(server)) + + # Downloading sosreport to local machine. + ret = copy_sosreports_to_dir(server, directory) + if not ret: + sys.exit("[ERROR]:Unable download sosreport from {}." + .format(server)) + print("[INFO]:Successfully copied sosreports from {}." + .format(server)) + + # If servers aren't provided. + except UnboundLocalError: + sys.exit("[ERROR]:servers were not provided") + + +if __name__ == "__main__": + main() diff --git a/tools/get_sosreports/setup.py b/tools/get_sosreports/setup.py new file mode 100644 index 000000000..79392e7ec --- /dev/null +++ b/tools/get_sosreports/setup.py @@ -0,0 +1,33 @@ +# Copyright (C) 2020 Red Hat, Inc. <http://www.redhat.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY :or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +from setuptools import setup + +setup( + name='get_sosreports', + version="1.0", + author='Red Hat, Inc.', + author_email='gluster-devel@gluster.org', + url='http://www.gluster.org', + licens="GPLv3+", + description=("Tool to collect sosreports" + " from all servers and clients"), + py_modules=['get_sosreports'], + entry_points=""" + [console_scripts] + get_sosreports = get_sosreports:main + """ +) diff --git a/tools/log_splitter/README.md b/tools/log_splitter/README.md new file mode 100644 index 000000000..e44aaecd3 --- /dev/null +++ b/tools/log_splitter/README.md @@ -0,0 +1,37 @@ +# log_splitter +Tool to split glusto logs to individual testcase logs. + +## Prerequisites +Python 3.x + +## Installation +1. Change directory to the project directory. + +``` +# cd tools/log_splitter +``` + +2. Now run the installation script. + +``` +# python3 setup.py install +``` + +3. To check run: + +``` +# log_splitter --help +``` + +## Usage +Just pass glusto_test.log file to the script as shown below: + +``` +# log_splitter -f glusto_test.log +``` + +**Note**: +The default destination directory is `.` (present dir) `-d` or `--dist-dir` option. + +## Licence +[GPLv3](https://github.com/gluster/glusto-tests/blob/master/LICENSE) diff --git a/tools/log_splitter/log_splitter.py b/tools/log_splitter/log_splitter.py new file mode 100644 index 000000000..e433b3ee1 --- /dev/null +++ b/tools/log_splitter/log_splitter.py @@ -0,0 +1,100 @@ +# Copyright (C) 2020 Red Hat, Inc. <http://www.redhat.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY :or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +# Imports needed by the script. +import argparse +import os +import sys + + +def check_and_create_dir_if_not_present(directory): + """ + A function to check and create directory if not present + + Args: + directory(str): Directory to be created if not present + + Retuns: + bool: True if successful else False + """ + if not os.path.isdir(directory): + cmd = "mkdir -p {}".format(directory) + ret = os.system(cmd) + if ret: + return False + print("[INFO]: Dir created successfully") + else: + print("[INFO]: The dir already exists") + return True + + +def main(): + """ + Main function of the tool. + """ + # Setting up command line arguments. + parser = argparse.ArgumentParser( + description="Tool to split glusto logs to individual testcase logs." + ) + parser.add_argument( + '-f', '--log_file', type=str, dest='log_file', required=True, + help="Glusto test log file") + parser.add_argument( + '-d', '--dist-dir', type=str, default=".", dest="destination_dir", + help="Path were individual test logs are to be stored.") + args = parser.parse_args() + + # Fetching the values from command line. + log_file = args.log_file + destination_dir = args.destination_dir + + # Check and create dir if not present + if not check_and_create_dir_if_not_present(destination_dir): + sys.exit("[ERROR]: Unable to create dir") + + with open(log_file, 'r', encoding="ISO-8859-1") as log_file_fd: + + # Read lines and set flag to check if + # file is open + file_open_flag = False + while True: + line = log_file_fd.readline() + if not line: + break + + # Check if line is starting line. + if '(setUp) Starting Test : ' in line: + if file_open_flag: + file_open_flag = False + + # Open new fd for individual test + # file + filename = line.split(' ')[7] + if destination_dir != '.': + filename = os.path.join(destination_dir, + filename) + file_open_flag = True + + # Write lines to individual test file + if file_open_flag: + with open(filename, 'w') as test_file: + test_file.write(line) + + print("[INFO]: Log file split completed") + + +if __name__ == "__main__": + main() diff --git a/tools/log_splitter/setup.py b/tools/log_splitter/setup.py new file mode 100644 index 000000000..2d922f30a --- /dev/null +++ b/tools/log_splitter/setup.py @@ -0,0 +1,33 @@ +# Copyright (C) 2020 Red Hat, Inc. <http://www.redhat.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY :or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +from setuptools import setup + +setup( + name='log_splitter', + version="1.0", + author='Red Hat, Inc.', + author_email='gluster-devel@gluster.org', + url='http://www.gluster.org', + licens="GPLv3+", + description=("Tool to split glusto logs to " + "individual testcase logs."), + py_modules=['log_splitter'], + entry_points=""" + [console_scripts] + log_splitter = log_splitter:main + """ +) diff --git a/tools/setup_passwordless_ssh/README.md b/tools/setup_passwordless_ssh/README.md new file mode 100644 index 000000000..c122d3703 --- /dev/null +++ b/tools/setup_passwordless_ssh/README.md @@ -0,0 +1,47 @@ +# setup_passwordless_ssh +This is a tool to setup passwordless ssh to all nodes. It takes a glusto-tests +config file and password as input. + +## Prerequisites +1. Python 3.x +2. All the servers should have the same password. +3. Install sshpass on the control node. + +``` +# yum install sshpass +``` + +## Installation +Download the project files from github. + +``` +# git clone https://github.com/gluster/glusto-tests.git +``` +Change directory to the project directory. + +``` +# cd glusto-tests/tool/setup_passwordless_ssh/ +``` +Now run the installation script. + +``` +# python3 setup.py install +``` +To check run: + +``` +setup_passwordless_ssh --help +``` + +## Usage +To use this you need to have a valid glusto-tests config file([Sample file](https://github.com/gluster/glusto-tests/tree/master/tests/)) +after which just run the tool as shown below: + +``` +# setup_passwordless_ssh -c <Config file> -p <Password> +``` +If you wish to establish passwordless ssh for a non-root user use `-u` or +`--username` option followed by the username. + +## License +[GPLv3](https://github.com/gluster/glusto-tests/blob/master/LICENSE)
\ No newline at end of file diff --git a/tools/setup_passwordless_ssh/setup.py b/tools/setup_passwordless_ssh/setup.py new file mode 100644 index 000000000..6a8a49936 --- /dev/null +++ b/tools/setup_passwordless_ssh/setup.py @@ -0,0 +1,31 @@ +#!/usr/bin/python3 +# Copyright (C) 2019 Red Hat, Inc. <http://www.redhat.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY :or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +from setuptools import setup + +setup( + name='setup_passwordless_ssh', + author='Red Hat, Inc.', + author_email='gluster-devel@gluster.org', + url='http://www.gluster.org', + license='GPLv3+', + description=("Tool to setup passwordless ssh to all nodes."), + py_modules=['setup_passwordless_ssh'], + entry_points=""" + [console_scripts] + setup_passwordless_ssh = setup_passwordless_ssh:main + """ +) diff --git a/tools/setup_passwordless_ssh/setup_passwordless_ssh.py b/tools/setup_passwordless_ssh/setup_passwordless_ssh.py new file mode 100644 index 000000000..e9a619c50 --- /dev/null +++ b/tools/setup_passwordless_ssh/setup_passwordless_ssh.py @@ -0,0 +1,147 @@ +#!/usr/bin/env python3 +# Copyright (C) 2019 Red Hat, Inc. <http://www.redhat.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY :or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +import argparse +import sys +from os import system +from yaml import safe_load + + +def read_config_file(config_file): + """ + A function to read the yaml file given to the script. + Args: + config_file(str): A config file used to run glusto-tests. + Return: + dict: A dictornary with all the details from config file. + """ + return safe_load(open(config_file, 'r')) + + +def setup_passwordless_ssh(server, username, password): + """ + A function to setup passwordless ssh to all servers. + Args: + server(str): hostname/IP of server for + passwordless ssh has to be configured. + username(str): User to be used to login. + password(str): password to be used to login. + Returns: + bool: True if successful else false. + """ + command = ("sshpass -p %s ssh-copy-id -o StrictHostKeyChecking=no %s@%s" + % (password, username, server)) + ret = system(command) + return not ret + + +def check_passwordless_ssh_setup(server, username): + """ + A function to check if passwordless ssh setup was successfull or not. + Args: + server(str): hostname/IP of server for + passwordless ssh has to be configured. + username(str): User to be used to login. + Returns: + bool: True if successful else false. + """ + command = ("ssh %s@%s hostname" % (username, server)) + ret = system(command) + return not ret + + +def main(): + """ + Main function of the tool. + """ + + # Setting up command line arguments. + parser = argparse.ArgumentParser( + description="Tool to setup passwordless ssh to all nodes." + ) + parser.add_argument("-c", "--config_file", + type=str, dest="config_file", + help="A glusto-tests configuration file.") + parser.add_argument("-p", "--password", dest="password", + type=str, help="Password of servers.") + parser.add_argument("-u", "--username", dest="username", + type=str, default="root", + help="User to be used to setup" + " passwordless ssh.") + args = parser.parse_args() + + # Reading the config file. + if args.config_file: + config = read_config_file(args.config_file) + else: + sys.exit("[ERROR]:Config file not provided.") + + # Checking if password was provided. + if args.password: + password = args.password + else: + sys.exit("[ERROR]:Password not provided.") + + # Configuring passwordless ssh to all servers. + for server in config.get('servers', []): + ret = setup_passwordless_ssh(server, args.username, + password) + if not ret: + sys.exit("[ERROR]:Unable to setup " + "passwordless ssh to %s." + % server) + ret = check_passwordless_ssh_setup(server, + args.username) + if ret: + print("[INFO]:Passwordless ssh setup " + "completed to %s." % server) + + # Configuring passwordless ssh to all clients. + for server in config.get('clients', []): + ret = setup_passwordless_ssh(server, + args.username, + password) + + if not ret: + sys.exit("[ERROR]:Unable to setup " + "passwordless ssh to %s." + % server) + + ret = check_passwordless_ssh_setup(server, + args.username) + if ret: + print("[INFO]:Passwordless ssh setup " + "completed to %s." % server) + + # Configure paswordless ssh to all geo-rep slaves nodes. + for server in config.get('slaves', []): + ret = setup_passwordless_ssh(server, + args.username, + password) + if not ret: + sys.exit("[ERROR]:Unable to setup " + "passwordless ssh to %s." + % server) + ret = check_passwordless_ssh_setup(server, + args.username) + if ret: + print("[INFO]:Passwordless ssh setup " + "completed to %s." % server) + + +if __name__ == "__main__": + main() diff --git a/tools/verify_test_execution/README.md b/tools/verify_test_execution/README.md new file mode 100644 index 000000000..d78819515 --- /dev/null +++ b/tools/verify_test_execution/README.md @@ -0,0 +1,38 @@ +# verify_test_execution +This tool verifies the stability of a given set of testcase(s) by executing it +consecutively for a pre-defined number of times. This ensures that the written +code is stable and also helps the user to identify unexpected failures or errors +that may arise while executing it multiple times. It also checks the given code +for any pylint/flake8 issues. + +## Prerequisites +Python 3.x + +To use this you need to have a valid glusto-tests config file + +## Usage +- Download the project files from github. + + ``` + # git clone https://github.com/gluster/glusto-tests.git + ``` +- Change directory to the project directory. + ``` + # cd glusto-tests/tool/verify_test_execution/ + ``` +- To get help run: + ``` + # python3 verify_test_execution.py --help + ``` +- To run the test(s): + ``` + # python3 verify_test_execution.py --config < Config file> --test <test_path> + ``` + +If you wish to specify the commands for flake8 and pylint (optional) use +`--flake8 <flake8 cmd> `and `--pylint <pylint command>` arguments. +Also, use `--iterations` to specify the number of times the test(s) +should be run (by default its 5) eg. `-- iterations 10 ` + +## License +GPLv3 diff --git a/tools/verify_test_execution/verify_test_execution.py b/tools/verify_test_execution/verify_test_execution.py new file mode 100644 index 000000000..1cfc3143e --- /dev/null +++ b/tools/verify_test_execution/verify_test_execution.py @@ -0,0 +1,157 @@ +# Copyright (C) 2020 Red Hat, Inc. <http://www.redhat.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY :or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +import argparse +import subprocess +import sys +from datetime import datetime + + +class TestVerify: + + def __init__(self): + self.parser = argparse.ArgumentParser() + self.config = None + self.test_path = None + self.test_run_count = None + self.pre_run_check = False + iter_value_default = 5 + flake8_default = "flake8" + pylint_default = "pylint" + # Set the arguments + self.parser.add_argument('-c', '--config', + help='Path to config file', + required=True) + self.parser.add_argument('-t', '--test', + help='path to test file/folder', + required=True) + self.parser.add_argument('-f', '--flake8', + default=flake8_default, + help='command to invoke flake8 ' + '(by default <flake8 path_to_py_file>)') + self.parser.add_argument('-p', '--pylint', + default=pylint_default, + help='command to invoke pylint ' + '(by default <pylint path_to_py_file>)') + self.parser.add_argument('-i', '--iterations', + type=int, + default=iter_value_default, + help='Iterations to runs the tests ' + '(by default its 5)') + args = self.parser.parse_args() + + # Get config file path + self.config = args.config + + # Get test file or folder + self.test_path = args.test + + # Get the pylint command + self.pylint_cmd = args.pylint + + # Get the falke8 command + self.flake8_cmd = args.flake8 + + # Get the iteration count + self.test_run_count = args.iterations + + # Verify flake8 + self.verify_flake8() + + # Verify Pylint + self.verify_pylint() + + # Verify test run for user defined number of times + self.execute_tests() + + def verify_pylint(self): + """ + Verifies the given file has pylint issues or not. + In case the path given for the test to execute is a folder, the pylint + command returns all the issues in all the files present in the folder. + Verifies the return code of pylint. + """ + print("o Pylint Verification:") + result = subprocess.run([self.pylint_cmd, self.test_path], + stdout=subprocess.PIPE) + if result.returncode != 0: + self._print_error(result.stdout) + print("\t Pylint validation failed") + self.pre_run_check = False + else: + print("\t Pylint validation successful") + self.pre_run_check = True + + def verify_flake8(self): + """ + Verifies the given file for falke8 issues. Executes the flake8 command + and verifies the return code. + """ + print("o Flake8 Verification:") + result = subprocess.run([self.flake8_cmd, self.test_path], + stdout=subprocess.PIPE) + if result.returncode != 0: + self._print_error(result.stdout) + sys.exit("[ERROR]: Flake8 validation Failed") + print("\t Flake8 validation successful") + + def execute_tests(self): + """ + Runs the given test for user defined number of times. + """ + start_time = datetime.now() + if not self.pre_run_check: + print("========= WARNING =========") + decision = input("There were some errors in the pre-check for " + "the given code. It is advised to fix all those " + "issues and the start executing the tests. To " + "continue to test execution press Y. To exit " + "press any other key : ") + if decision.lower() != "y": + sys.exit("[ERROR]: Aborted by user") + cmd = ("glusto -c '{config_path}' --pytest='-v -x {test_path}'" + .format(config_path=self.config, test_path=self.test_path)) + print("\no Run Tests") + print("\t ==>[ ", cmd, " ]") + for counter in range(1, self.test_run_count+1): + print("\t Iteration : %s" % counter) + process = subprocess.Popen(cmd, shell=True, + stdout=subprocess.PIPE) + process.wait() + if process.returncode != 0: + self._print_error(process.stdout.read()) + sys.exit("[ERROR]: Test Execution Failed") + print("\n\t\t Status : PASS") + end_time = datetime.now() + print("[INFO] : Test Execution succeeded") + print("\t Test : {test_name}".format(test_name=self.test_path)) + print("\t Iterations : {iter}".format(iter=str(self.test_run_count))) + print("\t Completed in {time}".format(time=str(end_time-start_time))) + + @staticmethod + def _print_error(err): + """ + Prints the error from the stdout + """ + print("\t [Error] \n\t", "-" * 100) + output = err.decode("utf-8").split("\n") + for line in output: + if line: + print("\t", str(line)) + print("\t", "-" * 100) + + +if __name__ == "__main__": + TestVerify() |